├── config ├── prod.json └── dev.json ├── favicon.ico ├── assets ├── icon.png ├── sidebar.jpg ├── Index Demo.png ├── Login Screen Demo.png ├── Loading Screen Demo.png ├── Course Selection Screen.png ├── ion-send-sharp.svg ├── ion-search-outline.svg ├── ion-home-outline.svg ├── ion-list-outline.svg ├── ion-settings-outline.svg ├── Blue Cat-1s-200px.svg ├── undraw_education_f8ru.svg └── undraw_programming_2svr.svg ├── icon-512x512.png ├── renderer ├── sections │ ├── schedule.html │ ├── main.html │ ├── setting.html │ └── school_timetable_query.html ├── css │ ├── fontawesome │ │ └── webfonts │ │ │ ├── fa-solid-900.eot │ │ │ ├── fa-solid-900.ttf │ │ │ ├── fa-brands-400.eot │ │ │ ├── fa-brands-400.ttf │ │ │ ├── fa-brands-400.woff │ │ │ ├── fa-brands-400.woff2 │ │ │ ├── fa-regular-400.eot │ │ │ ├── fa-regular-400.ttf │ │ │ ├── fa-regular-400.woff │ │ │ ├── fa-solid-900.woff │ │ │ ├── fa-solid-900.woff2 │ │ │ └── fa-regular-400.woff2 │ ├── simple-scrollbar.css │ ├── MHModal.css │ ├── tabs.css │ └── wannaclass.css.map ├── scss │ ├── wannaclass.scss │ ├── _typography.scss │ ├── _hover.scss │ ├── _global.scss │ ├── materializecss │ │ ├── _modal.scss │ │ └── _tapTarget.scss │ ├── _content-page.scss │ ├── _variables.scss │ ├── _sidebar.scss │ ├── _login-page.scss │ ├── _color-variables.scss │ └── _normalize.scss ├── js │ ├── content.js │ ├── navigate.js │ ├── preload_main.js │ ├── landing.js │ ├── query.js │ ├── simple-scrollbar.js │ ├── app_vue.js │ └── yzu_backend.js ├── CourseSelWorker.html └── index.html ├── package.json ├── .gitignore ├── README.md └── app.js /config/prod.json: -------------------------------------------------------------------------------- 1 | { 2 | 3 | } -------------------------------------------------------------------------------- /favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MissterHao/WannaClass/HEAD/favicon.ico -------------------------------------------------------------------------------- /assets/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MissterHao/WannaClass/HEAD/assets/icon.png -------------------------------------------------------------------------------- /assets/sidebar.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MissterHao/WannaClass/HEAD/assets/sidebar.jpg -------------------------------------------------------------------------------- /config/dev.json: -------------------------------------------------------------------------------- 1 | { 2 | "width": 800, 3 | "height": 600, 4 | "show" : false 5 | } -------------------------------------------------------------------------------- /icon-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MissterHao/WannaClass/HEAD/icon-512x512.png -------------------------------------------------------------------------------- /assets/Index Demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MissterHao/WannaClass/HEAD/assets/Index Demo.png -------------------------------------------------------------------------------- /assets/Login Screen Demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MissterHao/WannaClass/HEAD/assets/Login Screen Demo.png -------------------------------------------------------------------------------- /assets/Loading Screen Demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MissterHao/WannaClass/HEAD/assets/Loading Screen Demo.png -------------------------------------------------------------------------------- /assets/Course Selection Screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MissterHao/WannaClass/HEAD/assets/Course Selection Screen.png -------------------------------------------------------------------------------- /renderer/sections/schedule.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /renderer/css/fontawesome/webfonts/fa-solid-900.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MissterHao/WannaClass/HEAD/renderer/css/fontawesome/webfonts/fa-solid-900.eot -------------------------------------------------------------------------------- /renderer/css/fontawesome/webfonts/fa-solid-900.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MissterHao/WannaClass/HEAD/renderer/css/fontawesome/webfonts/fa-solid-900.ttf -------------------------------------------------------------------------------- /renderer/css/fontawesome/webfonts/fa-brands-400.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MissterHao/WannaClass/HEAD/renderer/css/fontawesome/webfonts/fa-brands-400.eot -------------------------------------------------------------------------------- /renderer/css/fontawesome/webfonts/fa-brands-400.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MissterHao/WannaClass/HEAD/renderer/css/fontawesome/webfonts/fa-brands-400.ttf -------------------------------------------------------------------------------- /renderer/css/fontawesome/webfonts/fa-brands-400.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MissterHao/WannaClass/HEAD/renderer/css/fontawesome/webfonts/fa-brands-400.woff -------------------------------------------------------------------------------- /renderer/css/fontawesome/webfonts/fa-brands-400.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MissterHao/WannaClass/HEAD/renderer/css/fontawesome/webfonts/fa-brands-400.woff2 -------------------------------------------------------------------------------- /renderer/css/fontawesome/webfonts/fa-regular-400.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MissterHao/WannaClass/HEAD/renderer/css/fontawesome/webfonts/fa-regular-400.eot -------------------------------------------------------------------------------- /renderer/css/fontawesome/webfonts/fa-regular-400.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MissterHao/WannaClass/HEAD/renderer/css/fontawesome/webfonts/fa-regular-400.ttf -------------------------------------------------------------------------------- /renderer/css/fontawesome/webfonts/fa-regular-400.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MissterHao/WannaClass/HEAD/renderer/css/fontawesome/webfonts/fa-regular-400.woff -------------------------------------------------------------------------------- /renderer/css/fontawesome/webfonts/fa-solid-900.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MissterHao/WannaClass/HEAD/renderer/css/fontawesome/webfonts/fa-solid-900.woff -------------------------------------------------------------------------------- /renderer/css/fontawesome/webfonts/fa-solid-900.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MissterHao/WannaClass/HEAD/renderer/css/fontawesome/webfonts/fa-solid-900.woff2 -------------------------------------------------------------------------------- /renderer/css/fontawesome/webfonts/fa-regular-400.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MissterHao/WannaClass/HEAD/renderer/css/fontawesome/webfonts/fa-regular-400.woff2 -------------------------------------------------------------------------------- /assets/ion-send-sharp.svg: -------------------------------------------------------------------------------- 1 | Send -------------------------------------------------------------------------------- /assets/ion-search-outline.svg: -------------------------------------------------------------------------------- 1 | Search -------------------------------------------------------------------------------- /assets/ion-home-outline.svg: -------------------------------------------------------------------------------- 1 | Home -------------------------------------------------------------------------------- /renderer/scss/wannaclass.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | // Color 4 | @import "color-variables"; 5 | 6 | // Variables; 7 | @import "variables"; 8 | 9 | // Reset 10 | @import "normalize"; 11 | 12 | 13 | // Typography 14 | @import "typography"; 15 | 16 | 17 | @import "materializecss/tapTarget"; 18 | @import "materializecss/modal"; 19 | 20 | // Global Settings 21 | @import "global"; 22 | 23 | // Login Page 24 | @import "login-page"; 25 | 26 | // Content Page 27 | @import "content-page"; 28 | 29 | @import "sidebar"; 30 | 31 | 32 | @import "hover"; -------------------------------------------------------------------------------- /assets/ion-list-outline.svg: -------------------------------------------------------------------------------- 1 | List -------------------------------------------------------------------------------- /renderer/js/content.js: -------------------------------------------------------------------------------- 1 | { 2 | var start = new Date().getFullYear() - 1911; 3 | 4 | ["#querySelectQueryYear", 5 | "#querySelectQueryYear_forCourseName", 6 | "#querySelectQueryYear_forTeacherName", 7 | "#querySelectQueryYear_forQueryTime"].forEach((n)=>{ 8 | 9 | for(var i in [...Array(5).keys()]){ 10 | 11 | var option = document.createElement("option") 12 | option.value = `${start-1 + parseInt(i)}`; 13 | option.textContent = `${start-1 + parseInt(i)}`; 14 | 15 | document.querySelector(n).appendChild(option) 16 | 17 | } 18 | 19 | }) 20 | } -------------------------------------------------------------------------------- /renderer/js/navigate.js: -------------------------------------------------------------------------------- 1 | var currentSectionId = ""; 2 | 3 | function hideAllSection(){ 4 | document.querySelectorAll(".inner-section").forEach((element)=>{ 5 | element.classList.remove("is-shown"); 6 | }) 7 | 8 | document.querySelectorAll(".sidebar-item").forEach((element)=>{ 9 | element.classList.remove("active") 10 | }) 11 | } 12 | 13 | function showSectionById(section) { 14 | hideAllSection() 15 | const sectionID = `section-${section}` 16 | 17 | document.querySelector(`#${section}-sidebar-item`).classList.add("active") 18 | document.getElementById(sectionID).classList.add('is-shown'); 19 | currentSectionId = section; 20 | } 21 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "wannaclass", 3 | "version": "1.0.0", 4 | "description": "Get class from yzu course api.", 5 | "main": "app.js", 6 | "scripts": { 7 | "start": "electron ." 8 | }, 9 | "keywords": [ 10 | "electron" 11 | ], 12 | "homepage": "https://github.com/MissterHao/WannaClass/", 13 | "bugs": { 14 | "url" : "https://github.com/MissterHao/WannaClass/issues", 15 | "email" : "henryliking@gmail.com" 16 | }, 17 | "author": { 18 | "name": "Hao-Wei, Li", 19 | "email": "henryliking@gmail.com" 20 | }, 21 | "license": "ISC", 22 | "devDependencies": { 23 | "electron": "^12.0.5", 24 | "electron-builder": "^22.10.5" 25 | }, 26 | "dependencies": { 27 | "@fortawesome/fontawesome-svg-core": "^1.2.30", 28 | "axios": "^0.21.1", 29 | "moment": "^2.29.1", 30 | "node-rsa": "^1.1.1", 31 | "request": "^2.88.2", 32 | "sqlite3": "^5.0.2", 33 | "vue": "^3.0.11" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /renderer/sections/main.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | note.md 2 | dev.js 3 | build/* 4 | *.sqlite 5 | config/settings.json 6 | settings.json 7 | 8 | .DS_Store 9 | .env 10 | .gclient_done 11 | **/.npmrc 12 | .tags* 13 | .vs/ 14 | .vscode/ 15 | *.log 16 | *.pyc 17 | *.sln 18 | *.swp 19 | *.VC.db 20 | *.VC.VC.opendb 21 | *.vcxproj 22 | *.vcxproj.filters 23 | *.vcxproj.user 24 | *.xcodeproj 25 | /.idea/ 26 | /dist/ 27 | node_modules/ 28 | SHASUMS256.txt 29 | **/package-lock.json 30 | compile_commands.json 31 | .envrc 32 | 33 | # npm package 34 | /npm/dist 35 | /npm/path.txt 36 | 37 | .npmrc 38 | 39 | # Generated API definitions 40 | electron-api.json 41 | electron.d.ts 42 | 43 | # Spec hash calculation 44 | spec/.hash 45 | 46 | # Eslint Cache 47 | .eslintcache* 48 | 49 | # Generated native addon files 50 | /spec-main/fixtures/native-addon/echo/build/ 51 | 52 | # If someone runs tsc this is where stuff will end up 53 | ts-gen 54 | 55 | # Used to accelerate CI builds 56 | .depshash 57 | .depshash-target 58 | 59 | # Used to accelerate builds after sync 60 | patches/mtime-cache.json 61 | 62 | spec/fixtures/logo.png -------------------------------------------------------------------------------- /renderer/css/simple-scrollbar.css: -------------------------------------------------------------------------------- 1 | .ss-wrapper { 2 | overflow: hidden; 3 | width: 100%; 4 | height: 100%; 5 | position: relative; 6 | z-index: 1; 7 | float: left; 8 | } 9 | 10 | .ss-content { 11 | height: 100%; 12 | width: calc(100% + 18px); 13 | padding: 0 0 0 0; 14 | position: relative; 15 | overflow-x: auto; 16 | overflow-y: scroll; 17 | box-sizing: border-box; 18 | } 19 | 20 | .ss-content.rtl { 21 | width: calc(100% + 18px); 22 | right: auto; 23 | } 24 | 25 | .ss-scroll { 26 | position: relative; 27 | background: rgba(0, 0, 0, 0.1); 28 | width: 9px; 29 | border-radius: 4px; 30 | top: 0; 31 | z-index: 2; 32 | cursor: pointer; 33 | opacity: 0; 34 | transition: opacity 0.25s linear; 35 | } 36 | 37 | .ss-hidden { 38 | display: none; 39 | } 40 | 41 | .ss-container:hover .ss-scroll, 42 | .ss-container:active .ss-scroll { 43 | opacity: 1; 44 | } 45 | 46 | .ss-grabbed { 47 | -o-user-select: none; 48 | -ms-user-select: none; 49 | -moz-user-select: none; 50 | -webkit-user-select: none; 51 | user-select: none; 52 | } 53 | -------------------------------------------------------------------------------- /renderer/js/preload_main.js: -------------------------------------------------------------------------------- 1 | const { 2 | contextBridge, 3 | ipcRenderer 4 | } = require("electron"); 5 | 6 | 7 | 8 | contextBridge.exposeInMainWorld( 9 | "tasks", { 10 | 11 | 12 | addTaskList: (channel, data) => { 13 | 14 | console.log(channel, data); 15 | 16 | // whitelist channels 17 | let validChannels = ["addTaskList:toMain"]; 18 | if (validChannels.includes(channel)) { 19 | ipcRenderer.send(channel, data); 20 | } 21 | }, 22 | 23 | 24 | // send: (channel, data) => { 25 | // // whitelist channels 26 | // let validChannels = ["toMain"]; 27 | // if (validChannels.includes(channel)) { 28 | // ipcRenderer.send(channel, data); 29 | // } 30 | // }, 31 | // receive: (channel, func) => { 32 | // let validChannels = ["fromMain"]; 33 | // if (validChannels.includes(channel)) { 34 | // // Deliberately strip event as it includes `sender` 35 | // ipcRenderer.on(channel, (event, ...args) => func(...args)); 36 | // } 37 | // } 38 | } 39 | ); -------------------------------------------------------------------------------- /assets/ion-settings-outline.svg: -------------------------------------------------------------------------------- 1 | Settings -------------------------------------------------------------------------------- /renderer/scss/_typography.scss: -------------------------------------------------------------------------------- 1 | 2 | a { 3 | text-decoration: none; 4 | } 5 | 6 | html{ 7 | line-height: 1.5; 8 | 9 | @media only screen and (min-width: 0) { 10 | font-size: 14px; 11 | } 12 | 13 | @media only screen and (min-width: $medium-screen) { 14 | font-size: 14.5px; 15 | } 16 | 17 | @media only screen and (min-width: $large-screen) { 18 | font-size: 15px; 19 | } 20 | 21 | font-family: $font-stack; 22 | font-weight: normal; 23 | color: $off-black; 24 | } 25 | h1, h2, h3, h4, h5, h6 { 26 | font-weight: 400; 27 | line-height: 1.3; 28 | } 29 | 30 | // Header Styles 31 | h1 a, h2 a, h3 a, h4 a, h5 a, h6 a { font-weight: inherit; } 32 | h1 { font-size: $h1-fontsize; line-height: 110%; margin: ($h1-fontsize / 1.5) 0 ($h1-fontsize / 2.5) 0;} 33 | h2 { font-size: $h2-fontsize; line-height: 110%; margin: ($h2-fontsize / 1.5) 0 ($h2-fontsize / 2.5) 0;} 34 | h3 { font-size: $h3-fontsize; line-height: 110%; margin: ($h3-fontsize / 1.5) 0 ($h3-fontsize / 2.5) 0;} 35 | h4 { font-size: $h4-fontsize; line-height: 110%; margin: ($h4-fontsize / 1.5) 0 ($h4-fontsize / 2.5) 0;} 36 | h5 { font-size: $h5-fontsize; line-height: 110%; margin: ($h5-fontsize / 1.5) 0 ($h5-fontsize / 2.5) 0;} 37 | h6 { font-size: $h6-fontsize; line-height: 110%; margin: ($h6-fontsize / 1.5) 0 ($h6-fontsize / 2.5) 0;} 38 | 39 | // Text Styles 40 | em { font-style: italic; } 41 | strong { font-weight: 500; } 42 | small { font-size: 75%; } 43 | .light { font-weight: 300; } 44 | .thin { font-weight: 200; } -------------------------------------------------------------------------------- /renderer/scss/_hover.scss: -------------------------------------------------------------------------------- 1 | 2 | /* Bounce To Right */ 3 | .hvr-bounce-to-right { 4 | display: inline-block; 5 | vertical-align: middle; 6 | -webkit-transform: perspective(1px) translateZ(0); 7 | transform: perspective(1px) translateZ(0); 8 | box-shadow: 0 0 1px rgba(0, 0, 0, 0); 9 | position: relative; 10 | -webkit-transition-property: color; 11 | transition-property: color; 12 | -webkit-transition-duration: 0.5s; 13 | transition-duration: 0.5s; 14 | } 15 | .hvr-bounce-to-right:before { 16 | content: ""; 17 | position: absolute; 18 | z-index: -1; 19 | top: 0; 20 | left: 0; 21 | right: 0; 22 | bottom: 0; 23 | background: #8ab3ca; 24 | -webkit-transform: scaleX(0); 25 | transform: scaleX(0); 26 | -webkit-transform-origin: 0 50%; 27 | transform-origin: 0 50%; 28 | -webkit-transition-property: transform; 29 | transition-property: transform; 30 | -webkit-transition-duration: 0.5s; 31 | transition-duration: 0.5s; 32 | -webkit-transition-timing-function: ease-out; 33 | transition-timing-function: ease-out; 34 | } 35 | .hvr-bounce-to-right:hover, .hvr-bounce-to-right:focus, .hvr-bounce-to-right:active { 36 | color: white; 37 | } 38 | .hvr-bounce-to-right:hover:before, .hvr-bounce-to-right:focus:before, .hvr-bounce-to-right:active:before { 39 | -webkit-transform: scaleX(1); 40 | transform: scaleX(1); 41 | -webkit-transition-timing-function: cubic-bezier(0.52, 1.64, 0.37, 0.66); 42 | transition-timing-function: cubic-bezier(0.52, 1.64, 0.37, 0.66); 43 | } 44 | -------------------------------------------------------------------------------- /renderer/scss/_global.scss: -------------------------------------------------------------------------------- 1 | @import url('https://fonts.googleapis.com/css2?family=Noto+Sans+TC&display=swap'); 2 | 3 | html, 4 | body { 5 | height : 100vh; 6 | max-width : 100vw; 7 | overflow-x: hidden; 8 | overflow-y: hidden; 9 | 10 | font-family: 'Noto Sans TC', sans-serif; 11 | } 12 | 13 | 14 | .section { 15 | height : 100vh; 16 | max-width : 100vw; 17 | overflow-x: hidden; 18 | overflow-y: hidden; 19 | } 20 | 21 | #app { 22 | position: relative; 23 | } 24 | 25 | .wc-container { 26 | margin : 0 auto; 27 | max-width: 1280px; 28 | width : 90%; 29 | } 30 | 31 | .hidden { 32 | display: none; 33 | // animation: hidden-disapear-anim 2s normal forwards ease-in-out; 34 | } 35 | 36 | 37 | 38 | .slide-up { 39 | position: absolute; 40 | z-index: 1000; 41 | transform: translateY(-100%); 42 | transition: all .8s cubic-bezier(0.6, -0.28, 0.735, 0.045); 43 | 44 | } 45 | 46 | 47 | .hidden-disapear { 48 | animation: hidden-disapear-anim 2s normal forwards ease-in-out; 49 | } 50 | .hidden-onshown { 51 | animation: hidden-onshown-anim 2s normal forwards ease-in-out; 52 | } 53 | 54 | @keyframes hidden-disapear-anim { 55 | 0% { 56 | opacity: 1; 57 | } 58 | 59 | 99% { 60 | opacity: 0; 61 | } 62 | 63 | 100% { 64 | opacity: 0; 65 | display: none; 66 | } 67 | } 68 | 69 | @keyframes hidden-onshown-anim { 70 | 0% { 71 | opacity: 0; 72 | display: none; 73 | } 74 | 1% { 75 | display: unset; 76 | } 77 | 78 | 79 | 80 | 100% { 81 | opacity: 1; 82 | } 83 | } 84 | 85 | 86 | #loading-panel { 87 | display: flex; 88 | flex-direction: column; 89 | align-items: center; 90 | justify-content: center; 91 | 92 | z-index: 1000; 93 | 94 | background: hsla(0, 0%, 100%, 0.884); 95 | } 96 | 97 | 98 | .point-it { 99 | cursor: pointer; 100 | } -------------------------------------------------------------------------------- /renderer/scss/materializecss/_modal.scss: -------------------------------------------------------------------------------- 1 | .modal { 2 | &:focus { 3 | outline: none; 4 | } 5 | box-shadow: 0 24px 38px 3px rgba(0,0,0,0.14), 6 | 0 9px 46px 8px rgba(0,0,0,0.12), 7 | 0 11px 15px -7px rgba(0,0,0,0.2); 8 | 9 | display: none; 10 | position: fixed; 11 | left: 0; 12 | right: 0; 13 | background-color: #fafafa; 14 | padding: 0; 15 | max-height: 70%; 16 | width: 55%; 17 | margin: auto; 18 | overflow-y: auto; 19 | 20 | border-radius: 2px; 21 | will-change: top, opacity; 22 | 23 | // @media #{$medium-and-down} { 24 | // width: 80%; 25 | // } 26 | 27 | h1,h2,h3,h4 { 28 | margin-top: 0; 29 | } 30 | 31 | .modal-content { 32 | padding: 24px; 33 | height: 100%; 34 | } 35 | .modal-close { 36 | cursor: pointer; 37 | } 38 | 39 | .modal-footer { 40 | border-radius: 0 0 2px 2px; 41 | background-color: #fafafa; 42 | padding: 4px 6px; 43 | height: 56px; 44 | width: 100%; 45 | text-align: right; 46 | 47 | .btn, .btn-flat { 48 | margin: 6px 0; 49 | } 50 | } 51 | } 52 | .modal-overlay { 53 | position: fixed; 54 | z-index: 999; 55 | top: -25%; 56 | left: 0; 57 | bottom: 0; 58 | right: 0; 59 | height: 125%; 60 | width: 100%; 61 | background: #000; 62 | display: none; 63 | 64 | will-change: opacity; 65 | } 66 | 67 | // Modal with fixed action footer 68 | .modal.modal-fixed-footer { 69 | padding: 0; 70 | height: 70%; 71 | 72 | .modal-content { 73 | position: absolute; 74 | height: calc(100% - 56px); 75 | max-height: 100%; 76 | width: 100%; 77 | overflow-y: auto; 78 | } 79 | 80 | .modal-footer { 81 | border-top: 1px solid rgba(0,0,0,.1); 82 | position: absolute; 83 | bottom: 0; 84 | } 85 | } 86 | 87 | // Modal Bottom Sheet Style 88 | .modal.bottom-sheet { 89 | top: auto; 90 | bottom: -100%; 91 | margin: 0; 92 | width: 100%; 93 | max-height: 45%; 94 | border-radius: 0; 95 | will-change: bottom, opacity; 96 | } 97 | -------------------------------------------------------------------------------- /renderer/scss/_content-page.scss: -------------------------------------------------------------------------------- 1 | .content-panel { 2 | 3 | background : $background-color; 4 | display : flex; 5 | 6 | .content-panel__infogrid { 7 | display: grid; 8 | grid-template-columns: 3fr;// 2fr; 9 | grid-template-rows: 1fr 3fr; 10 | height:0%; 11 | width: 0%; 12 | } 13 | 14 | .content-panel__notifylist { 15 | grid-column: 1 / 2; 16 | grid-row: 1 / 2; 17 | 18 | padding: 1rem 1rem; 19 | 20 | overflow-x: hidden; 21 | overflow-y: auto; 22 | 23 | transition: all .8s cubic-bezier(0.68, -0.55, 0.265, 1.55); 24 | 25 | 26 | &-item { 27 | height: 30px; 28 | transition: all .8s cubic-bezier(0.68, -0.55, 0.265, 1.55); 29 | 30 | display: flex; 31 | justify-content: space-between; 32 | align-items: center; 33 | 34 | width: 100%; 35 | overflow-x: hidden; 36 | } 37 | } 38 | 39 | // .content-panel__coursetable { 40 | // grid-column: 1 / 3; 41 | // grid-row: 2 / 3; 42 | // background: burlywood; 43 | // } 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | } 53 | 54 | #inner-content-panel { 55 | width: 100%; 56 | height: 100%; 57 | flex: 1 0 80%; 58 | 59 | overflow-x: hidden; 60 | overflow-y: auto; 61 | position: relative; 62 | } 63 | 64 | .inner-section { 65 | width: 100%; 66 | height: 100%; 67 | position: absolute; 68 | top: 0; 69 | left: 0; 70 | 71 | overflow-y: auto; 72 | 73 | visibility: hidden; 74 | opacity: 0; 75 | 76 | &.is-shown { 77 | visibility: visible; 78 | opacity: 1; 79 | transition: all 0.3s ease-in-out; 80 | } 81 | 82 | h4 { 83 | padding: 0 2rem; 84 | } 85 | } 86 | 87 | 88 | 89 | 90 | 91 | 92 | .courses-list { 93 | height: 100%; 94 | // overflow-y: scroll; 95 | padding: 2rem; 96 | } 97 | 98 | 99 | #section-Main { 100 | overflow: hidden; 101 | 102 | .header { 103 | height: 100%; 104 | width: 100%; 105 | } 106 | } -------------------------------------------------------------------------------- /renderer/js/landing.js: -------------------------------------------------------------------------------- 1 | document.addEventListener("DOMContentLoaded", (event)=>{ 2 | 3 | 4 | // Landing page cta button 5 | const cta = document.querySelector(".login-panel .cta") 6 | 7 | // Hero text and image 8 | const heroHeader = document.querySelector(".login-panel .hero-text h2") 9 | const heroDesc = document.querySelector(".login-panel .hero-text .hero-desc") 10 | const heroContent = document.querySelector(".login-panel .hero-text") 11 | 12 | // 13 | const heroImage = document.querySelector(".login-panel .hero-image img") 14 | const heroImageData = [ 15 | { 16 | src: "../assets/undraw_programming_2svr.svg", 17 | header: "半夜依舊在電腦前守著?", 18 | content: "黑眼圈熬出來也不一定搶得到課R!" 19 | }, 20 | { 21 | src: "../assets/undraw_education_f8ru.svg", 22 | header: "給自己的學分一點機會", 23 | content: "" 24 | }, 25 | { 26 | src: "../assets/undraw_schedule_pnbk.svg", 27 | header: "還不知道下學期課表?", 28 | content: "查課表不想再輸入驗證碼?" 29 | }, 30 | 31 | ] 32 | var heroImageIndex = 0; 33 | setInterval(() => { 34 | heroImageIndex = (heroImageIndex + 1) % 3; 35 | heroImage.setAttribute("src", heroImageData[heroImageIndex].src) 36 | heroHeader.textContent = heroImageData[heroImageIndex].header 37 | heroDesc.textContent = heroImageData[heroImageIndex].content 38 | }, 4000) 39 | 40 | 41 | 42 | // Login panel 43 | 44 | 45 | cta.onclick = function () { 46 | document.querySelector(".login-panel .hero-image").classList.toggle("move-to-hidden"); 47 | document.querySelector(".login-panel .hero-text").classList.toggle("move-to-hidden"); 48 | document.querySelector(".login-panel .login-block").classList.toggle("move-to-hidden"); 49 | 50 | if (cta.querySelector("i").classList.contains("fa-arrow-right")) { 51 | cta.querySelector("span").textContent = "返回首頁" 52 | } else { 53 | cta.querySelector("span").textContent = "開始使用" 54 | } 55 | cta.querySelector("i").classList.toggle("fa-arrow-right") 56 | cta.querySelector("i").classList.toggle("fa-arrow-left") 57 | } 58 | }) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 |

5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |

20 | 21 | # Wanna Class 元智選課系統 22 | 23 | 半夜依舊在電腦前守著? 24 | 想修熱門的課卻永遠搶不到? 25 | 查課表還在官網上輸入驗證碼慢慢搜尋? 26 | 27 | 那現在正是一個好時機嘗試全新的選課方式! 28 | 29 | 此軟體保證: 30 | 31 | + **不紀錄帳號密碼** 32 | 使用元智 Portal 帳號密碼登入,不須擔心帳號密碼會被盜用或記錄,程式碼完全公開接受開源社群的檢驗,絕對安全。 33 | + **不對電腦造成額外負擔** 34 | 不像其他程式會使用電腦挖礦,本程式使用最基本的方式簡化您電腦需要的資源! 35 | 36 | 37 | 38 | ## 左方列表功能: 39 | 40 | 41 | 42 | + 首頁 43 | 未來將會加入 「portal 通知列表」、「圖書館還書通知」等功能。 44 | + 課程查詢 45 | 快速查詢每學期的課表,點擊列表可以顯示該課程資訊(學分數、上課教室、教授名稱等資訊),列表最右方有「加入選課清單」按鈕可以加入選課任務列表中。 46 | + 選課任務列表 47 | 以列表方式顯示目前每一門課的選課進度(「尚未選到」、「已選到!恭喜!」、「此課程已選過喔!」以及「其他未明狀態 狀態碼 x」),若出現未明狀態可以通知作者喔! 48 | + 設定 49 | 設定選課的階段,根據元智選課方法,需要設定目前需要選課的階段(第一、第二、第三階段)才可選課。 50 | 51 | Index Screen 52 | Course Selection Screen 53 | Login Screen 54 | Loading Screen 55 | 56 | ## Future Feature 57 | 58 | * [ ] 任務控制鈕 59 | * [ ] 多國語系 60 | * [ ] 首頁顯示 Portal 通知 61 | * [ ] Unit Test 62 | * [ ] Mac application Build 63 | * [ ] Github Action CI 64 | * [ ] Github Action CD 65 | * [ ] Isolation Environment 66 | 67 | ## 作者聲明 68 | 69 | 本程式只供本人學術上的作品集使用喔! 70 | 71 | ## License 72 | 73 | This project is projected under GNU GPL v3 LICENCE. 74 | -------------------------------------------------------------------------------- /renderer/js/query.js: -------------------------------------------------------------------------------- 1 | 2 | var jsonArray = [ 3 | { "user": { "id": 100, "screen_name": "d_linq" }, "text": "to objects" }, 4 | { "user": { "id": 130, "screen_name": "c_bill" }, "text": "g" }, 5 | { "user": { "id": 155, "screen_name": "b_mskk" }, "text": "kabushiki kaisha" }, 6 | { "user": { "id": 301, "screen_name": "a_xbox" }, "text": "halo reach" } 7 | ] 8 | // ["b_mskk:kabushiki kaisha", "c_bill:g", "d_linq:to objects"] 9 | // var queryResult = Enumerable.from(jsonArray) 10 | // .where(function (x) { return x.user.id < 200 }) 11 | // .orderBy(function (x) { return x.user.screen_name }) 12 | // .select(function (x) { return x.user.screen_name + ':' + x.text }) 13 | // .toArray(); 14 | // console.log(queryResult); 15 | 16 | // queryResult = Enumerable.range(0, 20) 17 | // .where("x => x % 3 == 0") 18 | // .select("$ * 7") 19 | // console.log(queryResult); 20 | 21 | 22 | 23 | 24 | 25 | // function _queryByDept(){ 26 | 27 | // } 28 | 29 | 30 | 31 | 32 | 33 | 34 | // if(data["type"]=="dept"){ 35 | // courseDB.db.all("SELECT * from courses WHERE year = ? AND smtr = ? AND dept_name = ?", [data["data"]["Year"], data["data"]["Smt"], data["data"]["Dept"], ], (err, table)=>{ 36 | // console.log(table); 37 | // ipcRenderer.send(CHANNEL_NAME.TELL_MAIN_QUERY_COURSES__COMPLETE, {"result": table}) 38 | // }) 39 | // }else if(data["type"]=="courseName"){ 40 | // console.log(data); 41 | // var cn = "%"+data["data"]["CourseName"]+"%" 42 | 43 | // courseDB.db.all("SELECT * from courses WHERE name LIKE ? AND year = ? AND smtr = ?", [cn, data["data"]["Year"], data["data"]["Smt"]], (err, table)=>{ 44 | // console.log(table); 45 | // ipcRenderer.send(CHANNEL_NAME.TELL_MAIN_QUERY_COURSES__COMPLETE, {"result": table}) 46 | // }) 47 | // }else if(data["type"]=="teacherName"){ 48 | // var tn = "%"+data["data"]["TeacherName"]+"%" 49 | 50 | // courseDB.db.all("SELECT * from courses WHERE teacher_name LIKE ? AND year = ? AND smtr = ?", [tn, data["data"]["Year"], data["data"]["Smt"]], (err, table)=>{ 51 | // console.log(table); 52 | // ipcRenderer.send(CHANNEL_NAME.TELL_MAIN_QUERY_COURSES__COMPLETE, {"result": table}) 53 | // }) 54 | // }else if(data["type"]=="courseTime"){ 55 | // var tn = "%"+data["data"]["time"]+"%" 56 | // courseDB.db.all("SELECT * from courses WHERE time LIKE ? AND year = ? AND smtr = ?", [tn, data["data"]["Year"], data["data"]["Smt"]], (err, table)=>{ 57 | // console.log(table); 58 | // ipcRenderer.send(CHANNEL_NAME.TELL_MAIN_QUERY_COURSES__COMPLETE, {"result": table}) 59 | // }) 60 | // } 61 | -------------------------------------------------------------------------------- /renderer/scss/_variables.scss: -------------------------------------------------------------------------------- 1 | // ========================================================================== 2 | // Materialize variables 3 | // ========================================================================== 4 | // 5 | // Table of Contents: 6 | // 7 | // 1. Colors 8 | // 11. Global 9 | // 20. Typography 10 | 11 | 12 | 13 | // 1. Colors 14 | // ========================================================================== 15 | $background-color: #F5F5FC; 16 | $primary-color: #5776ad !default; 17 | $primary-color-light: lighten($primary-color, 15%) !default; 18 | $primary-color-dark: darken($primary-color, 15%) !default; 19 | 20 | $secondary-color: color("teal", "lighten-4") !default; 21 | 22 | $primary-text-color: white; 23 | $secondary-text-color: Black; 24 | 25 | 26 | // $primary-color: color("materialize-red", "lighten-2") !default; 27 | // $primary-color-light: lighten($primary-color, 15%) !default; 28 | // $primary-color-dark: darken($primary-color, 15%) !default; 29 | 30 | // $secondary-color: color("teal", "lighten-1") !default; 31 | // $success-color: color("green", "base") !default; 32 | // $error-color: color("red", "base") !default; 33 | // $link-color: color("light-blue", "darken-1") !default; 34 | 35 | 36 | 37 | // 11. Global 38 | // ========================================================================== 39 | 40 | // Media Query Ranges 41 | $small-screen-up: 601px !default; 42 | $medium-screen-up: 993px !default; 43 | $large-screen-up: 1201px !default; 44 | $small-screen: 600px !default; 45 | $medium-screen: 992px !default; 46 | $large-screen: 1200px !default; 47 | 48 | $medium-and-up: "only screen and (min-width : #{$small-screen-up})" !default; 49 | $large-and-up: "only screen and (min-width : #{$medium-screen-up})" !default; 50 | $extra-large-and-up: "only screen and (min-width : #{$large-screen-up})" !default; 51 | $small-and-down: "only screen and (max-width : #{$small-screen})" !default; 52 | $medium-and-down: "only screen and (max-width : #{$medium-screen})" !default; 53 | $medium-only: "only screen and (min-width : #{$small-screen-up}) and (max-width : #{$medium-screen})" !default; 54 | 55 | 56 | // 20. Typography 57 | // ========================================================================== 58 | 59 | $font-stack: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif !default; 60 | $off-black: rgba(0, 0, 0, 0.87) !default; 61 | // Header Styles 62 | $h1-fontsize: 4.2rem !default; 63 | $h2-fontsize: 3.56rem !default; 64 | $h3-fontsize: 2.92rem !default; 65 | $h4-fontsize: 2.28rem !default; 66 | $h5-fontsize: 1.64rem !default; 67 | $h6-fontsize: 1.15rem !default; 68 | -------------------------------------------------------------------------------- /renderer/scss/materializecss/_tapTarget.scss: -------------------------------------------------------------------------------- 1 | .tap-target-wrapper { 2 | width: 800px; 3 | height: 800px; 4 | position: fixed; 5 | z-index: 1000; 6 | visibility: hidden; 7 | transition: visibility 0s .3s; 8 | } 9 | 10 | .tap-target-wrapper.open { 11 | visibility: visible; 12 | transition: visibility 0s; 13 | 14 | .tap-target { 15 | transform: scale(1); 16 | opacity: .95; 17 | transition: 18 | transform .3s cubic-bezier(.42,0,.58,1), 19 | opacity .3s cubic-bezier(.42,0,.58,1); 20 | } 21 | 22 | .tap-target-wave::before { 23 | transform: scale(1); 24 | } 25 | .tap-target-wave::after { 26 | visibility: visible; 27 | animation: pulse-animation 1s cubic-bezier(0.24, 0, 0.38, 1) infinite; 28 | transition: 29 | opacity .3s, 30 | transform .3s, 31 | visibility 0s 1s; 32 | } 33 | } 34 | 35 | .tap-target { 36 | position: absolute; 37 | font-size: 1rem; 38 | border-radius: 50%; 39 | background-color: $primary-color; 40 | box-shadow: 0 20px 20px 0 rgba(0,0,0,0.14), 0 10px 50px 0 rgba(0,0,0,0.12), 0 30px 10px -20px rgba(0,0,0,0.2); 41 | width: 100%; 42 | height: 100%; 43 | opacity: 0; 44 | transform: scale(0); 45 | transition: 46 | transform .3s cubic-bezier(.42,0,.58,1), 47 | opacity .3s cubic-bezier(.42,0,.58,1); 48 | } 49 | 50 | .tap-target-content { 51 | position: relative; 52 | display: table-cell; 53 | } 54 | 55 | .tap-target-wave { 56 | &::before, 57 | &::after { 58 | content: ''; 59 | display: block; 60 | position: absolute; 61 | width: 100%; 62 | height: 100%; 63 | border-radius: 50%; 64 | background-color: #ffffff; 65 | } 66 | &::before { 67 | transform: scale(0); 68 | transition: transform .3s; 69 | } 70 | &::after { 71 | visibility: hidden; 72 | transition: 73 | opacity .3s, 74 | transform .3s, 75 | visibility 0s; 76 | z-index: -1; 77 | } 78 | 79 | position: absolute; 80 | border-radius: 50%; 81 | z-index: 10001; 82 | } 83 | 84 | .tap-target-origin { 85 | &:not(.btn), 86 | &:not(.btn):hover { 87 | background: none; 88 | } 89 | 90 | top: 50%; 91 | left: 50%; 92 | transform: translate(-50%,-50%); 93 | 94 | z-index: 10002; 95 | position: absolute; 96 | } 97 | 98 | @media only screen and (max-width: 600px) { 99 | .tap-target, .tap-target-wrapper { 100 | width: 600px; 101 | height: 600px; 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /renderer/sections/setting.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | const { app, BrowserWindow, ipcMain, Main } = require("electron"); 2 | const path = require("path"); 3 | const fs = require("fs") 4 | 5 | const renderer_dirpath = path.join("./", "renderer") 6 | 7 | var settingFilePath = "settings.json" 8 | 9 | let MainWindow = null 10 | let SelectCourseWorkerWindow = null 11 | var initConfigSettingJson = {"interval":2, "stage": "1"}; 12 | 13 | function readOrcreateSettingJson() { 14 | try { 15 | const content = fs.readFileSync(settingFilePath, "utf-8") 16 | } catch (error) { 17 | fs.writeFile(settingFilePath, JSON.stringify(initConfigSettingJson), "utf-8", function (err, data) {}) 18 | } 19 | } 20 | 21 | 22 | function createWindow() { 23 | readOrcreateSettingJson() 24 | 25 | 26 | // 建立 Browser Window 27 | MainWindow = new BrowserWindow({ 28 | width: 1200, 29 | height: 900, 30 | winWidth: 1000, 31 | winHeight: 800, 32 | transparent: false, 33 | 34 | // Remove the frame of the window 35 | frame: true, // 控制有沒有外框 36 | webPreferences: { 37 | nodeIntegration: true, 38 | contextIsolation: false, // 預設為 true 必須設為 false 39 | // preload: path.join(renderer_dirpath, "js", "preload_main.html"), 40 | } 41 | }) 42 | 43 | MainWindow.setMenuBarVisibility(false) 44 | MainWindow.loadFile(path.join(renderer_dirpath, "index.html")) 45 | // MainWindow.webContents.openDevTools(); 46 | 47 | 48 | 49 | 50 | 51 | // 建立選課worker window 52 | SelectCourseWorkerWindow = new BrowserWindow({ 53 | width: 0, 54 | height: 0, 55 | show: false, 56 | webPreferences: { 57 | nodeIntegration: true, 58 | contextIsolation: false, // 預設為 true 必須設為 false 59 | } 60 | }) 61 | SelectCourseWorkerWindow.loadFile(path.join(renderer_dirpath, "CourseSelWorker.html")) 62 | // SelectCourseWorkerWindow.openDevTools() 63 | 64 | 65 | 66 | 67 | // 在主畫面關閉時 關閉 Worker 68 | MainWindow.on("close", function () { 69 | SelectCourseWorkerWindow.close() 70 | 71 | // 確保刪除登入 Token 72 | var settings = fs.readFileSync(settingFilePath, "utf-8") 73 | settings["token"] = "" 74 | fs.writeFile(settingFilePath, JSON.stringify(settings), "utf-8", function (err, data) {}) 75 | 76 | }) 77 | 78 | 79 | 80 | 81 | } 82 | 83 | 84 | 85 | 86 | // 有些 API 只能在這個事件發生後才能用。 87 | app.whenReady().then(createWindow) 88 | 89 | // 處理離開時的狀態 90 | app.on('window-all-closed', () => { 91 | // 在 macOS 中,一般會讓應用程式及選單列繼續留著, 92 | // 除非使用者按了 Cmd + Q 確定終止它們 93 | if (process.platform !== 'darwin') { 94 | app.quit() 95 | } 96 | }) 97 | 98 | app.on('activate', () => { 99 | // 在 macOS 中,一般會在使用者按了 Dock 圖示 100 | // 且沒有其他視窗開啟的情況下, 101 | // 重新在應用程式裡建立視窗。 102 | if (BrowserWindow.getAllWindows().length === 0) { 103 | createWindow() 104 | } 105 | }) 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | // IPC 118 | ipcMain.on("addTaskCourse", (event, data)=>{ 119 | SelectCourseWorkerWindow.webContents.send("addTaskCourse", data); 120 | }) 121 | // IPC 重讀設定檔 122 | ipcMain.on("regetSettings", (event, data)=>{ 123 | SelectCourseWorkerWindow.webContents.send("regetSettings", data); 124 | }) -------------------------------------------------------------------------------- /renderer/css/MHModal.css: -------------------------------------------------------------------------------- 1 | .MHmodal-btn { 2 | position: relative; 3 | display: table-cell; 4 | width: 100px; 5 | height: 100px; 6 | background-color: #2c3e50; 7 | box-shadow: 0 0 40px rgba(0, 0, 0, 0.3); 8 | border-radius: 50%; 9 | font-size: 36px; 10 | color: black; 11 | text-align: center; 12 | line-height: 2.75; 13 | transition: box-shadow 250ms ease; 14 | } 15 | 16 | .MHmodal-btn:hover { 17 | box-shadow: 0 0 5px rgba(0, 0, 0, 0.3); 18 | } 19 | 20 | .MHmodal-bg { 21 | position: fixed; 22 | top: 0; 23 | left: 0; 24 | width: 100%; 25 | height: 100%; 26 | opacity: 0; 27 | z-index: 10; 28 | visibility: hidden; 29 | transition: background-color 250ms linear; 30 | } 31 | 32 | .MHmodal-content { 33 | position: fixed; 34 | top: 50%; 35 | left: 50%; 36 | width: 50%; 37 | height: auto; 38 | margin-top: -18%; 39 | margin-left: -25%; 40 | padding: 30px; 41 | background-color: white; 42 | border-radius: 4px; 43 | box-shadow: 0 0 50px rgba(0, 0, 0, 0.5); 44 | transform: scale(0); 45 | transition: transform 250ms ease; 46 | visibility: hidden; 47 | z-index: 20; 48 | 49 | color: black; 50 | } 51 | 52 | .MHmodal-content .close { 53 | position: relative; 54 | float: right; 55 | font-size: 18px; 56 | transition: transform 500ms ease; 57 | z-index: 11; 58 | } 59 | 60 | .MHmodal-content .close:hover { 61 | color: #3498db; 62 | transform: rotate(540deg); 63 | } 64 | 65 | .MHmodal-content header { 66 | position: relative; 67 | display: block; 68 | border-bottom: 1px solid #eee; 69 | } 70 | 71 | .MHmodal-content header h2 { 72 | margin: 0 0 10px; 73 | padding: 0; 74 | font-size: 28px; 75 | } 76 | 77 | .MHmodal-content article { 78 | position: relative; 79 | display: block; 80 | margin: 0; 81 | padding: 0; 82 | font-size: 16px; 83 | line-height: 1.75; 84 | } 85 | 86 | .MHmodal-content footer { 87 | position: relative; 88 | display: flex; 89 | align-items: center; 90 | justify-content: flex-end; 91 | width: 100%; 92 | margin: 0; 93 | padding: 10px 0 0; 94 | } 95 | 96 | .MHmodal-content footer .button { 97 | position: relative; 98 | padding: 10px 30px; 99 | border-radius: 3px; 100 | font-size: 14px; 101 | font-weight: 400; 102 | color: black; 103 | text-transform: uppercase; 104 | overflow: hidden; 105 | } 106 | 107 | .MHmodal-content footer .button:before { 108 | position: absolute; 109 | content: ''; 110 | top: 0; 111 | left: 0; 112 | width: 0; 113 | height: 100%; 114 | background-color: rgba(255, 255, 255, 0.2); 115 | transition: width 250ms ease; 116 | z-index: 0; 117 | } 118 | 119 | .MHmodal-content footer .button:hover:before { 120 | width: 100%; 121 | } 122 | 123 | .MHmodal-content footer .button.success { 124 | margin-right: 5px; 125 | background-color: #2ecc71; 126 | } 127 | 128 | .MHmodal-content footer .button.danger { 129 | background-color: #e74c3c; 130 | margin-bottom: 0; 131 | } 132 | 133 | #MHmodal { 134 | display: none; 135 | } 136 | 137 | #MHmodal:checked~.MHmodal-bg { 138 | visibility: visible; 139 | background-color: black; 140 | opacity: 0.7; 141 | transition: background-color 250ms linear; 142 | } 143 | 144 | #MHmodal:checked~.MHmodal-content { 145 | visibility: visible; 146 | transform: scale(1); 147 | transition: transform 250ms ease; 148 | z-index: 111; 149 | } -------------------------------------------------------------------------------- /renderer/scss/_sidebar.scss: -------------------------------------------------------------------------------- 1 | $background: white; 2 | 3 | 4 | // normal state 5 | $sidebar-item-normal-text-color: black; 6 | $sidebar-item-normal-background-color: white; 7 | 8 | // hover state 9 | $sidebar-item-hover-text-color: white; 10 | $sidebar-item-hover-background-color: $primary-color-light; 11 | $sidebar-item-hover-radius: 0; 12 | 13 | // active state 14 | $sidebar-item-active-text-color: white; 15 | $sidebar-item-active-background-color: $primary-color-dark; 16 | $sidebar-item-active-radius: 0; 17 | 18 | 19 | .sidebar { 20 | width: 100%; 21 | height: 100vh; 22 | 23 | overflow: hidden; 24 | 25 | flex: 0 0 20%; 26 | 27 | display: flex; 28 | flex-direction: column; 29 | align-items: center; 30 | justify-content: start; 31 | 32 | padding-bottom: 2rem; 33 | 34 | background-color: $background; 35 | 36 | 37 | &.shrink { 38 | flex: 0 0 5%; 39 | 40 | .sidebar-item { 41 | padding-left: 0px; 42 | padding-right: 0px; 43 | justify-content: center; 44 | 45 | &:hover { 46 | border-radius: 0; 47 | color: $primary-color-dark; 48 | } 49 | > img { 50 | margin: 0; 51 | } 52 | > span { 53 | display: none; 54 | } 55 | } 56 | } 57 | 58 | 59 | .sidebar-funcitonal-items { 60 | width: 100%; 61 | } 62 | 63 | 64 | 65 | &-item { 66 | width: 100%; 67 | padding-top: 20px; 68 | padding-bottom: 20px; 69 | 70 | padding-left: 2rem; 71 | 72 | display: flex; 73 | 74 | color: $sidebar-item-normal-text-color; 75 | background-color: sidebar-item-normal-background-color; 76 | 77 | transition: all .3s cubic-bezier(0.445, 0.05, 0.55, 0.95); 78 | 79 | &:hover { 80 | color: $sidebar-item-hover-text-color; 81 | background-color: $sidebar-item-hover-background-color; 82 | fill: $sidebar-item-hover-text-color; 83 | 84 | border-top-right-radius: $sidebar-item-hover-radius $sidebar-item-hover-radius; 85 | border-bottom-right-radius: $sidebar-item-hover-radius $sidebar-item-hover-radius; 86 | 87 | img { 88 | //white 89 | // caculate by https://codepen.io/sosuke/pen/Pjoqqp 90 | filter: invert(100%) sepia(100%) saturate(0%) hue-rotate(288deg) brightness(102%) contrast(102%); 91 | } 92 | } 93 | 94 | &.active { 95 | color: $sidebar-item-active-text-color; 96 | background-color: $sidebar-item-active-background-color; 97 | fill: $sidebar-item-active-text-color; 98 | 99 | border-top-right-radius: $sidebar-item-active-radius $sidebar-item-active-radius; 100 | border-bottom-right-radius: $sidebar-item-active-radius $sidebar-item-active-radius; 101 | 102 | img { 103 | //white 104 | // caculate by https://codepen.io/sosuke/pen/Pjoqqp 105 | filter: invert(100%) sepia(100%) saturate(0%) hue-rotate(288deg) brightness(102%) contrast(102%); 106 | } 107 | } 108 | 109 | img { 110 | width: 20px; 111 | margin-right: 1rem; 112 | } 113 | 114 | } 115 | 116 | 117 | 118 | #author-sidebar-item { 119 | // background-image: url("../assets/ion-settings-outline.svg"); 120 | margin-top: auto; 121 | } 122 | 123 | 124 | 125 | } 126 | 127 | 128 | 129 | .header { 130 | flex: 0 0 10%; 131 | padding: 10px 0px; 132 | 133 | width: 100%; 134 | height: 100%; 135 | display: flex; 136 | justify-content: center; 137 | align-items: center; 138 | } 139 | 140 | -------------------------------------------------------------------------------- /assets/Blue Cat-1s-200px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /renderer/CourseSelWorker.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Get Course Window 8 | 9 | 10 | 11 | 131 | 132 | 133 | -------------------------------------------------------------------------------- /renderer/js/simple-scrollbar.js: -------------------------------------------------------------------------------- 1 | ;(function(root, factory) { 2 | if (typeof exports === 'object') { 3 | module.exports = factory(window, document) 4 | } else { 5 | root.SimpleScrollbar = factory(window, document) 6 | } 7 | })(this, function(w, d) { 8 | var raf = w.requestAnimationFrame || w.setImmediate || function(c) { return setTimeout(c, 0); }; 9 | 10 | function initEl(el) { 11 | Object.defineProperty(el, 'data-simple-scrollbar', { value: new SimpleScrollbar(el), configurable: true }); 12 | } 13 | 14 | function unbindEl(el) { 15 | if (!Object.prototype.hasOwnProperty.call(el, 'data-simple-scrollbar')) return; 16 | el['data-simple-scrollbar'].unBind(); 17 | //Remove the elements property 18 | delete el['data-simple-scrollbar']; 19 | } 20 | 21 | // Mouse drag handler 22 | function dragDealer(el, context) { 23 | var lastPageY; 24 | 25 | el.addEventListener('mousedown', function(e) { 26 | lastPageY = e.pageY; 27 | el.classList.add('ss-grabbed'); 28 | d.body.classList.add('ss-grabbed'); 29 | 30 | d.addEventListener('mousemove', drag); 31 | d.addEventListener('mouseup', stop); 32 | 33 | return false; 34 | }); 35 | 36 | function drag(e) { 37 | var delta = e.pageY - lastPageY; 38 | lastPageY = e.pageY; 39 | 40 | raf(function() { 41 | context.el.scrollTop += delta / context.scrollRatio; 42 | }); 43 | } 44 | 45 | function stop() { 46 | el.classList.remove('ss-grabbed'); 47 | d.body.classList.remove('ss-grabbed'); 48 | d.removeEventListener('mousemove', drag); 49 | d.removeEventListener('mouseup', stop); 50 | } 51 | } 52 | 53 | // Constructor 54 | function ss(el) { 55 | this.target = el; 56 | this.content = el.firstElementChild; 57 | 58 | this.direction = w.getComputedStyle(this.target).direction; 59 | 60 | this.bar = '
'; 61 | //Create a reference to the function binding to remove the event listeners 62 | this.mB = this.moveBar.bind(this); 63 | 64 | this.wrapper = d.createElement('div'); 65 | this.wrapper.setAttribute('class', 'ss-wrapper'); 66 | 67 | this.el = d.createElement('div'); 68 | this.el.setAttribute('class', 'ss-content'); 69 | 70 | if (this.direction === 'rtl') { 71 | this.el.classList.add('rtl'); 72 | } 73 | 74 | this.wrapper.appendChild(this.el); 75 | 76 | while (this.target.firstChild) { 77 | this.el.appendChild(this.target.firstChild); 78 | } 79 | this.target.appendChild(this.wrapper); 80 | 81 | this.target.insertAdjacentHTML('beforeend', this.bar); 82 | this.bar = this.target.lastChild; 83 | 84 | dragDealer(this.bar, this); 85 | this.moveBar(); 86 | 87 | w.addEventListener('resize', this.mB); 88 | this.el.addEventListener('scroll', this.mB); 89 | this.el.addEventListener('mouseenter', this.mB); 90 | 91 | this.target.classList.add('ss-container'); 92 | 93 | var css = w.getComputedStyle(el); 94 | if (css['height'] === '0px' && css['max-height'] !== '0px') { 95 | el.style.height = css['max-height']; 96 | } 97 | 98 | this.unBind = function() { 99 | //Remove event listeners 100 | w.removeEventListener('resize', this.mB); 101 | this.el.removeEventListener('scroll', this.mB); 102 | this.el.removeEventListener('mouseenter', this.mB); 103 | 104 | this.target.classList.remove('ss-container'); 105 | 106 | //Unwrap the initial content and remove remaining wrappers 107 | this.target.insertBefore(this.content, this.wrapper); 108 | this.target.removeChild(this.wrapper); 109 | 110 | //Remove the bar including its drag-dealer event listener 111 | this.target.removeChild(this.bar); 112 | this.bar = null; //make way for the garbage collector 113 | } 114 | } 115 | 116 | ss.prototype = { 117 | moveBar: function(e) { 118 | var totalHeight = this.el.scrollHeight, 119 | ownHeight = this.el.clientHeight, 120 | _this = this; 121 | 122 | this.scrollRatio = ownHeight / totalHeight; 123 | 124 | var isRtl = _this.direction === 'rtl'; 125 | var right = isRtl ? 126 | (_this.target.clientWidth - _this.bar.clientWidth + 18) : 127 | (_this.target.clientWidth - _this.bar.clientWidth) * -1; 128 | 129 | raf(function() { 130 | // Hide scrollbar if no scrolling is possible 131 | if(_this.scrollRatio >= 1) { 132 | _this.bar.classList.add('ss-hidden') 133 | } else { 134 | _this.bar.classList.remove('ss-hidden') 135 | _this.bar.style.cssText = 'height:' + Math.max(_this.scrollRatio * 100, 10) + '%; top:' + (_this.el.scrollTop / totalHeight ) * 100 + '%;right:' + right + 'px;'; 136 | } 137 | }); 138 | } 139 | } 140 | 141 | function initAll() { 142 | var nodes = d.querySelectorAll('*[ss-container]'); 143 | 144 | for (var i = 0; i < nodes.length; i++) { 145 | initEl(nodes[i]); 146 | } 147 | } 148 | 149 | function unbindAll() { 150 | var nodes = d.querySelectorAll('.ss-container'); 151 | 152 | for (var i = 0; i < nodes.length; i++) { 153 | unbindEl(nodes[i]); 154 | } 155 | } 156 | 157 | d.addEventListener('DOMContentLoaded', initAll); 158 | ss.initEl = initEl; 159 | ss.initAll = initAll; 160 | ss.unbindEl = unbindEl; 161 | ss.unbindAll = unbindAll; 162 | 163 | var SimpleScrollbar = ss; 164 | return SimpleScrollbar; 165 | }); 166 | -------------------------------------------------------------------------------- /assets/undraw_education_f8ru.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /renderer/scss/_login-page.scss: -------------------------------------------------------------------------------- 1 | .login-panel { 2 | background : $background-color; 3 | // background: url('https://images.pexels.com/photos/2922672/pexels-photo-2922672.jpeg') no-repeat; 4 | // background-position: center bottom; 5 | // background : url(../assets/programmer-transparent-bg.png); 6 | display : flex; 7 | flex-direction : column; 8 | position : relative; 9 | 10 | .header { 11 | padding : 0 5rem; 12 | flex : 1 1 10%; 13 | justify-content: start; 14 | align-items : flex-start; 15 | display : flex; 16 | flex-direction : column; 17 | color: $primary-color-dark; 18 | } 19 | 20 | .middle { 21 | flex : 1 1 100%; 22 | display : flex; 23 | flex-direction: row; 24 | align-content : center; 25 | 26 | 27 | .hero-image { 28 | z-index : 100; 29 | max-height : 80vh; 30 | overflow-y : hidden; 31 | display : flex; 32 | flex-direction : column; 33 | align-items : center; 34 | justify-content: center; 35 | 36 | img { 37 | animation : hidden-onshown-anim 2s normal forwards ease-in-out; 38 | margin : auto 0; 39 | max-width : 100%; 40 | transition: all 1s cubic-bezier(0.23, 1, 0.320, 1); 41 | opacity : 1; 42 | 43 | &.hidden { 44 | opacity: 0; 45 | } 46 | 47 | } 48 | 49 | flex: 0 0 60%; 50 | 51 | transition: all 1.3s cubic-bezier(0.445, 0.05, 0.55, 0.95); 52 | 53 | 54 | &.move-to-hidden { 55 | // flex : 0 0 0%; 56 | flex-basis: 0%; 57 | transform : translateX(-100%); 58 | } 59 | 60 | } 61 | 62 | .hero-text { 63 | flex : 0 0 40%; 64 | display : flex; 65 | flex-direction: column; 66 | align-items : start; 67 | padding : 10em 1rem 0 3rem; 68 | 69 | color : $primary-color-dark; 70 | transition: all 1.3s cubic-bezier(0.445, 0.05, 0.55, 0.95); 71 | 72 | 73 | 74 | h2 { 75 | word-wrap: break-word; 76 | } 77 | 78 | &.move-to-hidden { 79 | flex : 0 0 50%; 80 | align-items: start; 81 | } 82 | } 83 | 84 | .hero-desc { 85 | font-weight: 300; 86 | } 87 | 88 | .cta { 89 | background: white; 90 | box-shadow: rgb(145, 140, 140) 2px 2px; 91 | cursor : pointer; 92 | margin-top: 2rem; 93 | padding : 1em 4em; 94 | 95 | border-radius: 50px; 96 | color : $primary-color-dark; 97 | 98 | .fas { 99 | margin-left: 1rem; 100 | } 101 | } 102 | 103 | 104 | 105 | .login-block { 106 | flex : 0 0 40%; 107 | display : flex; 108 | flex-direction : column; 109 | justify-content: center; 110 | align-items : center; 111 | 112 | transform : scale(1); 113 | transition: all 1.3s cubic-bezier(0.445, 0.05, 0.55, 0.95); 114 | 115 | &.move-to-hidden { 116 | flex : 0 0 0%; 117 | transform: scale(0); 118 | } 119 | 120 | .login-block-lockimg { 121 | // width: 10rem; 122 | // height: 10rem; 123 | position : absolute; 124 | top : 0rem; 125 | right : 20px; 126 | font-size: 5rem; 127 | color : rgb(207, 205, 205); 128 | } 129 | 130 | .login-block-inner { 131 | height : 80%; 132 | margin-top : auto; 133 | margin-bottom: auto; 134 | background : white; 135 | 136 | border-radius: 5px; 137 | 138 | display : flex; 139 | flex-direction: column; 140 | padding : 2rem; 141 | padding-top : 3.5rem; 142 | 143 | position: relative; 144 | } 145 | 146 | .login-block-inner-input-group { 147 | width : 100%; 148 | height : 100%; 149 | display : flex; 150 | flex-direction: column; 151 | } 152 | 153 | .login-block-input-element { 154 | width : 100%; 155 | background: #eff0f2; 156 | 157 | margin : .8em 0; 158 | padding : .8em 0; 159 | line-height: 1.5; 160 | transition : border-color calc(1 * 1s) ease; 161 | text-align : center; 162 | 163 | outline : transparent; 164 | border : 0px; 165 | border-style : solid; 166 | border-radius: 28px; 167 | } 168 | 169 | #login-btn { 170 | cursor : pointer; 171 | background: hsl(359, 96%, 78%); 172 | 173 | &:hover { 174 | background: hsl(359, 96%, 68%); 175 | } 176 | } 177 | } 178 | } 179 | 180 | .footer { 181 | flex : 1 1 10%; 182 | display : flex; 183 | justify-content: flex-end; 184 | 185 | ul { 186 | display : flex; 187 | font-size: 2rem; 188 | 189 | li { 190 | text-decoration: none; 191 | list-style : none; 192 | 193 | a { 194 | width : 50px; 195 | height: 50px; 196 | margin: 0 5px; 197 | 198 | text-decoration: none; 199 | color : $background-color; 200 | background : $primary-color-dark; 201 | border-radius : 50%; 202 | 203 | display : flex; 204 | justify-content: center; 205 | align-items : center; 206 | 207 | position: relative; 208 | 209 | cursor: pointer; 210 | 211 | transition: 0.3s; 212 | 213 | .fab { 214 | position: relative; 215 | z-index : 100; 216 | } 217 | 218 | &:hover { 219 | color: white; 220 | } 221 | 222 | &:hover:before { 223 | transform: scale(1); 224 | } 225 | 226 | &:before { 227 | content : ''; 228 | position : absolute; 229 | width : 100%; 230 | height : 100%; 231 | background : $primary-color-light; 232 | border-radius: 50%; 233 | transform : scale(0); 234 | transition : .5s; 235 | } 236 | 237 | } 238 | } 239 | } 240 | 241 | 242 | } 243 | } -------------------------------------------------------------------------------- /renderer/css/tabs.css: -------------------------------------------------------------------------------- 1 | @import "https://fonts.googleapis.com/css?family=Montserrat:400,700|Raleway:300,400"; 2 | /* colors */ 3 | /* tab setting */ 4 | /* breakpoints */ 5 | /* selectors relative to radio inputs */ 6 | 7 | /* color: black; */ 8 | .btabs { 9 | left: 50%; 10 | -webkit-transform: translateX(-50%); 11 | transform: translateX(-50%); 12 | position: relative; 13 | color: #efefef; 14 | padding: 50px; 15 | padding-bottom: 80px; 16 | width: 100%; 17 | height: 250px; 18 | /* box-shadow: 0 14px 28px rgba(255, 255, 255, 0.25), 0 10px 10px rgba(255, 255, 255, 0.22); */ 19 | border-radius: 5px; 20 | min-width: 240px; 21 | } 22 | .btabs input[name="query-tab-control"] { 23 | display: none; 24 | } 25 | .btabs .content section h2, 26 | .btabs ul li label { 27 | font-family: "Montserrat"; 28 | font-weight: bold; 29 | font-size: 18px; 30 | color: black; 31 | } 32 | .btabs ul { 33 | list-style-type: none; 34 | padding-left: 0; 35 | display: -webkit-box; 36 | display: flex; 37 | -webkit-box-orient: horizontal; 38 | -webkit-box-direction: normal; 39 | flex-direction: row; 40 | margin-bottom: 10px; 41 | -webkit-box-pack: justify; 42 | justify-content: space-between; 43 | -webkit-box-align: end; 44 | align-items: flex-end; 45 | flex-wrap: wrap; 46 | } 47 | .btabs ul li { 48 | box-sizing: border-box; 49 | -webkit-box-flex: 1; 50 | flex: 1; 51 | width: 25%; 52 | padding: 0 10px; 53 | text-align: center; 54 | } 55 | .btabs ul li label { 56 | -webkit-transition: all 0.3s ease-in-out; 57 | transition: all 0.3s ease-in-out; 58 | color: black; 59 | padding: 5px auto; 60 | overflow: hidden; 61 | text-overflow: ellipsis; 62 | display: block; 63 | cursor: pointer; 64 | -webkit-transition: all 0.2s ease-in-out; 65 | transition: all 0.2s ease-in-out; 66 | white-space: nowrap; 67 | -webkit-touch-callout: none; 68 | -webkit-user-select: none; 69 | -moz-user-select: none; 70 | -ms-user-select: none; 71 | user-select: none; 72 | } 73 | .btabs ul li label br { 74 | display: none; 75 | } 76 | .btabs ul li label svg { 77 | fill: #929daf; 78 | height: 1.2em; 79 | vertical-align: bottom; 80 | margin-right: 0.2em; 81 | -webkit-transition: all 0.2s ease-in-out; 82 | transition: all 0.2s ease-in-out; 83 | } 84 | .btabs ul li label:hover, .btabs ul li label:focus, .btabs ul li label:active { 85 | outline: 0; 86 | color: black; 87 | } 88 | .btabs ul li label:hover svg, .btabs ul li label:focus svg, .btabs ul li label:active svg { 89 | fill: black; 90 | } 91 | .btabs .slider { 92 | position: relative; 93 | width: 25%; 94 | -webkit-transition: all 0.33s cubic-bezier(0.38, 0.8, 0.32, 1.07); 95 | transition: all 0.33s cubic-bezier(0.38, 0.8, 0.32, 1.07); 96 | } 97 | .btabs .slider .indicator { 98 | position: relative; 99 | width: 50px; 100 | max-width: 100%; 101 | margin: 0 auto; 102 | height: 4px; 103 | background: black; 104 | border-radius: 1px; 105 | } 106 | .btabs .content { 107 | margin-top: 30px; 108 | } 109 | .btabs .content section { 110 | display: none; 111 | -webkit-animation-name: content; 112 | animation-name: content; 113 | -webkit-animation-direction: normal; 114 | animation-direction: normal; 115 | -webkit-animation-duration: 0.3s; 116 | animation-duration: 0.3s; 117 | -webkit-animation-timing-function: ease-in-out; 118 | animation-timing-function: ease-in-out; 119 | -webkit-animation-iteration-count: 1; 120 | animation-iteration-count: 1; 121 | line-height: 1.4; 122 | } 123 | .btabs .content section h2 { 124 | color: black; 125 | display: none; 126 | } 127 | .btabs .content section h2::after { 128 | content: ""; 129 | position: relative; 130 | display: block; 131 | width: 30px; 132 | height: 3px; 133 | background: black; 134 | margin-top: 5px; 135 | left: 1px; 136 | } 137 | .btabs input[name="query-tab-control"]:nth-of-type(1):checked ~ ul > li:nth-child(1) > label { 138 | cursor: default; 139 | color: black; 140 | } 141 | .btabs input[name="query-tab-control"]:nth-of-type(1):checked ~ ul > li:nth-child(1) > label svg { 142 | fill: black; 143 | } 144 | @media (max-width: 600px) { 145 | .btabs input[name="query-tab-control"]:nth-of-type(1):checked ~ ul > li:nth-child(1) > label { 146 | background: rgba(0, 0, 0, 0.08); 147 | } 148 | } 149 | .btabs input[name="query-tab-control"]:nth-of-type(1):checked ~ .slider { 150 | -webkit-transform: translateX(0%); 151 | transform: translateX(0%); 152 | } 153 | .btabs input[name="query-tab-control"]:nth-of-type(1):checked ~ .content > section:nth-child(1) { 154 | display: block; 155 | } 156 | .btabs input[name="query-tab-control"]:nth-of-type(2):checked ~ ul > li:nth-child(2) > label { 157 | cursor: default; 158 | color: black; 159 | } 160 | .btabs input[name="query-tab-control"]:nth-of-type(2):checked ~ ul > li:nth-child(2) > label svg { 161 | fill: black; 162 | } 163 | @media (max-width: 600px) { 164 | .btabs input[name="query-tab-control"]:nth-of-type(2):checked ~ ul > li:nth-child(2) > label { 165 | background: rgba(0, 0, 0, 0.08); 166 | } 167 | } 168 | .btabs input[name="query-tab-control"]:nth-of-type(2):checked ~ .slider { 169 | -webkit-transform: translateX(100%); 170 | transform: translateX(100%); 171 | } 172 | .btabs input[name="query-tab-control"]:nth-of-type(2):checked ~ .content > section:nth-child(2) { 173 | display: block; 174 | } 175 | .btabs input[name="query-tab-control"]:nth-of-type(3):checked ~ ul > li:nth-child(3) > label { 176 | cursor: default; 177 | color: black; 178 | } 179 | .btabs input[name="query-tab-control"]:nth-of-type(3):checked ~ ul > li:nth-child(3) > label svg { 180 | fill: black; 181 | } 182 | @media (max-width: 600px) { 183 | .btabs input[name="query-tab-control"]:nth-of-type(3):checked ~ ul > li:nth-child(3) > label { 184 | background: rgba(0, 0, 0, 0.08); 185 | } 186 | } 187 | .btabs input[name="query-tab-control"]:nth-of-type(3):checked ~ .slider { 188 | -webkit-transform: translateX(200%); 189 | transform: translateX(200%); 190 | } 191 | .btabs input[name="query-tab-control"]:nth-of-type(3):checked ~ .content > section:nth-child(3) { 192 | display: block; 193 | } 194 | .btabs input[name="query-tab-control"]:nth-of-type(4):checked ~ ul > li:nth-child(4) > label { 195 | cursor: default; 196 | color: black; 197 | } 198 | .btabs input[name="query-tab-control"]:nth-of-type(4):checked ~ ul > li:nth-child(4) > label svg { 199 | fill: black; 200 | } 201 | @media (max-width: 600px) { 202 | .btabs input[name="query-tab-control"]:nth-of-type(4):checked ~ ul > li:nth-child(4) > label { 203 | background: rgba(0, 0, 0, 0.08); 204 | } 205 | } 206 | .btabs input[name="query-tab-control"]:nth-of-type(4):checked ~ .slider { 207 | -webkit-transform: translateX(300%); 208 | transform: translateX(300%); 209 | } 210 | .btabs input[name="query-tab-control"]:nth-of-type(4):checked ~ .content > section:nth-child(4) { 211 | display: block; 212 | } 213 | @-webkit-keyframes content { 214 | from { 215 | opacity: 0; 216 | -webkit-transform: translateY(5%); 217 | transform: translateY(5%); 218 | } 219 | to { 220 | opacity: 1; 221 | -webkit-transform: translateY(0%); 222 | transform: translateY(0%); 223 | } 224 | } 225 | @keyframes content { 226 | from { 227 | opacity: 0; 228 | -webkit-transform: translateY(5%); 229 | transform: translateY(5%); 230 | } 231 | to { 232 | opacity: 1; 233 | -webkit-transform: translateY(0%); 234 | transform: translateY(0%); 235 | } 236 | } 237 | @media (max-width: 1000px) { 238 | .btabs ul li label { 239 | white-space: initial; 240 | } 241 | .btabs ul li label br { 242 | display: initial; 243 | } 244 | .btabs ul li label svg { 245 | height: 1.5em; 246 | } 247 | } 248 | @media (max-width: 600px) { 249 | .btabs ul li label { 250 | padding: 5px; 251 | border-radius: 5px; 252 | } 253 | .btabs ul li label span { 254 | display: none; 255 | } 256 | .btabs .slider { 257 | display: none; 258 | } 259 | .btabs .content { 260 | margin-top: 20px; 261 | } 262 | .btabs .content section h2 { 263 | display: block; 264 | } 265 | } 266 | -------------------------------------------------------------------------------- /renderer/js/app_vue.js: -------------------------------------------------------------------------------- 1 | const { ipcRenderer } = require("electron"); 2 | const { BackendService } = require("./js/yzu_backend"); 3 | const Enumerable = require("./js/linq") 4 | const { ref, onMounted, onUpdated, computed, watch } = Vue; 5 | var apibackend = new BackendService() 6 | 7 | const fs = require('fs'); 8 | var settingFilePath = "settings.json" 9 | let settings = JSON.parse(fs.readFileSync(settingFilePath)) 10 | 11 | var sqlite3 = require('sqlite3').verbose(); 12 | const database = new sqlite3.Database('db.sqlite'); 13 | 14 | 15 | var year_now = new Date().getFullYear() - 1911; 16 | var smtr_now = new Date().getMonth() >= 7 ? 1 : 2; 17 | 18 | function saveSettingFile(){ 19 | fs.writeFileSync(settingFilePath, JSON.stringify(settings)) 20 | } 21 | 22 | const app = Vue.createApp({ 23 | el: '#app', 24 | // delimiters: ['@{', '}'], 25 | setup() { 26 | /** 27 | * Variables 28 | */ 29 | const sid = ref(""); 30 | const spwd = ref(""); 31 | 32 | const greetings = ref("") 33 | 34 | const isLoading = ref(false); // 是否 35 | const loading_text = ref(""); 36 | 37 | const login_infomation = ref({}); // 儲存登入資訊 38 | const std_account_infomation = ref({}); // 儲存學生資訊 39 | const notify_list = ref([]); 40 | const dept_list = ref([]); // 總學校系級 41 | 42 | 43 | // School Timetable Query 44 | const queryType = ref("dept") // 欲搜尋的類型 45 | const querySelectQueryYear = ref(`${year_now}`) // 欲搜尋的學年 46 | const querySelectQuerySmt = ref(`${smtr_now}`) // 欲搜尋的學期 47 | const querySelectQueryDept = ref("") // 欲搜尋的系級 48 | 49 | const queryInputQueryCourseName = ref("") // 欲搜尋的課程名稱 50 | 51 | const queryInputQueryTeacherName = ref("") // 欲搜尋的教師名稱 52 | 53 | const querySelectQueryDay = ref("1") // 欲搜尋的星期 54 | const querySelectQueryPeriod = ref("01") // 欲搜尋的課堂時間 55 | 56 | const queryResultForList = ref([]) // 用於儲存已查詢到的課程列表 57 | const modalCourse = ref({}) // 用於儲存點擊的 Course Info 並顯示於 Modal 中 58 | var CourseList = []; // 總課程列表 59 | 60 | // Task List 61 | const tasks = ref([]); 62 | 63 | // Settings 64 | const StealCourseInterval = ref(settings.interval); // 選課時間間隔 65 | const StealCourseStage = ref(settings.stage); // 選課時間間隔 66 | 67 | /** 68 | * Functions 69 | */ 70 | // 登入並取得學生名字 71 | function login() { 72 | if (sid.value !== "" && spwd.value !== "") { 73 | 74 | loading_text.value = "登入中"; 75 | isLoading.value = true; 76 | 77 | 78 | apibackend._getRSAKey() 79 | .then((service) => { 80 | return service._encryptData(sid.value, spwd.value) 81 | }) 82 | .then((service) => { 83 | return service._getUserAccessToken() 84 | }).then((service) => { 85 | login_infomation.value = service.login_infomation; 86 | settings["token"] = login_infomation.value["Token"] 87 | saveSettingFile() 88 | return service._getAppLoginccount() 89 | }).then((service) => { 90 | std_account_infomation.value = service.std_account_infomation[0] 91 | getCourseList() 92 | getNotifyList() 93 | 94 | 95 | setTimeout(() => { 96 | isLoading.value = false; 97 | loading_text.value = ""; 98 | document.querySelector(".login-panel").classList.add("slide-up") 99 | 100 | setTimeout(() => { 101 | document.querySelector(".login-panel").style.display = "none"; 102 | document.querySelector(".login-panel").classList.remove("slide-up") 103 | }, 2000); 104 | 105 | // 顯示首頁 106 | showSectionById("Main") 107 | 108 | }, 2000) 109 | 110 | }) 111 | } 112 | } 113 | 114 | function showSection(id) { 115 | showSectionById(id) 116 | } 117 | 118 | function getCourseList() { 119 | 120 | loading_text.value = "下載課程資料中~"; 121 | isLoading.value = true; 122 | 123 | apibackend.getCourseListFromYZUApi(`${querySelectQueryYear.value}`, `${querySelectQuerySmt.value}`).then((data) => { 124 | CourseList = data.course_list; 125 | dept_list.value = data.dept_list; 126 | 127 | loading_text.value = "下載完成"; 128 | isLoading.value = false; 129 | }) 130 | 131 | } 132 | 133 | function getNotifyList() { 134 | apibackend.getNotifyList().then((service) => { 135 | notify_list.value = service.notify_list; 136 | var el = document.querySelector('.content-panel__notifylist'); 137 | SimpleScrollbar.initEl(el); 138 | }) 139 | } 140 | 141 | function query(qtype, ...args) { 142 | if (qtype == "dept") { 143 | var a = Enumerable.from(CourseList) 144 | .where((x) => { return x.year == args[0] && x.smtr == args[1] && x.dept_name.includes(args[2]) }) 145 | .select("$") 146 | .toArray(); 147 | queryResultForList.value = a; 148 | } else if (qtype == "courseName") { 149 | var a = Enumerable.from(CourseList) 150 | .where((x) => { return x.name == args[0] }) 151 | .select("$") 152 | .toArray(); 153 | queryResultForList.value = a; 154 | } else if (qtype == "teacherName") { 155 | var a = Enumerable.from(CourseList) 156 | .where((x) => { 157 | if (x.teacher_name === null) return false; 158 | 159 | return x.teacher_name.includes(args[0]) 160 | } 161 | 162 | ) 163 | .select("$") 164 | .toArray(); 165 | queryResultForList.value = a; 166 | } else if (qtype == "courseTime") { 167 | var time = args[0] + args[1]; 168 | var a = Enumerable.from(CourseList) 169 | .where((x) => { 170 | if (x.time === null) return false; 171 | return x.time.includes(time) 172 | } 173 | ) 174 | .select("$") 175 | .toArray(); 176 | queryResultForList.value = a; 177 | } 178 | } 179 | 180 | watch([querySelectQueryYear, querySelectQuerySmt], ([newYear, newSmt], [prevYear, prevSmt]) => { 181 | getCourseList() 182 | }) 183 | watch(querySelectQueryDept, (newDept, prevDept) => { 184 | query(queryType.value, querySelectQueryYear.value, querySelectQuerySmt.value, newDept) 185 | }) 186 | watch([querySelectQueryDay, querySelectQueryPeriod,], ([newDay, newPeriod], [prevDay, prevPeriod]) => { 187 | query(queryType.value, newDay, newPeriod) 188 | }) 189 | watch(queryInputQueryCourseName, (newCN, prevCN) => { 190 | query(queryType.value, newCN) 191 | }) 192 | watch(queryInputQueryTeacherName, (newTN, prevTN) => { 193 | query(queryType.value, newTN) 194 | }) 195 | watch(queryType, (newqueryType, prevqueryType) => { 196 | 197 | // querySelectQueryYear.value = "" 198 | // querySelectQuerySmt.value = "" 199 | querySelectQueryDept.value = "" 200 | 201 | queryInputQueryCourseName.value = "" 202 | 203 | queryInputQueryTeacherName.value = "" 204 | 205 | querySelectQueryDay.value = "1" 206 | querySelectQueryPeriod.value = "01" 207 | 208 | queryResultForList.value = [] 209 | }) 210 | 211 | watch(StealCourseInterval, (newInterval, prevInterval) => { 212 | settings["interval"] = parseInt(newInterval) 213 | saveSettingFile() 214 | ipcRenderer.send("regetSettings", {}) 215 | }) 216 | 217 | watch(StealCourseStage, (newStage, prevStage) => { 218 | settings["stage"] = newStage 219 | saveSettingFile() 220 | ipcRenderer.send("regetSettings", {}) 221 | }) 222 | 223 | function addToSchedule(event, course) { 224 | event.preventDefault() 225 | event.stopPropagation() 226 | // 通知 worker 加入搶課列表 227 | var course_obj = JSON.parse(JSON.stringify(course)) 228 | console.log(course_obj); 229 | ipcRenderer.send("addTaskCourse", course_obj) 230 | 231 | } 232 | 233 | function showCourseInfo(course) { 234 | modalCourse.value = course; 235 | document.querySelector("#MHmodal").checked = true; 236 | } 237 | 238 | function status(s) { 239 | if (s == 0) { 240 | return "尚未選到" 241 | } else if (s == 1) { 242 | return "已選到!恭喜!" 243 | } else if (s == 2) { 244 | return "此課程已選過喔!" 245 | } else { 246 | return `其他未明狀態 狀態碼 ${s}` 247 | } 248 | } 249 | 250 | onUpdated(() => { }) 251 | 252 | onMounted(() => { 253 | setInterval(() => { 254 | database.all(`SELECT * FROM tasks`, [], (err, rows) => { 255 | if (err) { 256 | throw err; 257 | } 258 | tasks.value = rows 259 | }); 260 | }, 5000) 261 | 262 | 263 | document.addEventListener('DOMContentLoaded', function () { 264 | // var options = {}; 265 | // var elems = document.querySelectorAll(".tap-target"); 266 | // var instances = M.TapTarget.init(elems, options); 267 | 268 | var options = {}; 269 | var elems = document.querySelectorAll('.modal'); 270 | var instances = M.Modal.init(elems, options); 271 | }) 272 | }) 273 | 274 | return { 275 | // Util UI variable 276 | greetings, 277 | // student login infomation 278 | sid, spwd, login, 279 | // student infomation 280 | std_account_infomation, 281 | notify_list, 282 | // UI controlling 283 | isLoading, loading_text, 284 | dept_list, 285 | showSection, 286 | // School Timetable Query 287 | addToSchedule, showCourseInfo, 288 | queryType, querySelectQueryYear, querySelectQuerySmt, querySelectQueryDept, queryInputQueryCourseName, 289 | queryInputQueryTeacherName, querySelectQueryDay, querySelectQueryPeriod, queryResultForList, modalCourse, 290 | // Task List 291 | tasks, status, 292 | // Settings 293 | StealCourseInterval, StealCourseStage, 294 | } 295 | } 296 | }); 297 | 298 | app.mount('#app') 299 | -------------------------------------------------------------------------------- /renderer/scss/_color-variables.scss: -------------------------------------------------------------------------------- 1 | // Google Color Palette defined: http://www.google.com/design/spec/style/color.html 2 | 3 | $materialize-red: ( 4 | "base": #e51c23, 5 | "lighten-5": #fdeaeb, 6 | "lighten-4": #f8c1c3, 7 | "lighten-3": #f3989b, 8 | "lighten-2": #ee6e73, 9 | "lighten-1": #ea454b, 10 | "darken-1": #d0181e, 11 | "darken-2": #b9151b, 12 | "darken-3": #a21318, 13 | "darken-4": #8b1014, 14 | ); 15 | 16 | $red: ( 17 | "base": #F44336, 18 | "lighten-5": #FFEBEE, 19 | "lighten-4": #FFCDD2, 20 | "lighten-3": #EF9A9A, 21 | "lighten-2": #E57373, 22 | "lighten-1": #EF5350, 23 | "darken-1": #E53935, 24 | "darken-2": #D32F2F, 25 | "darken-3": #C62828, 26 | "darken-4": #B71C1C, 27 | "accent-1": #FF8A80, 28 | "accent-2": #FF5252, 29 | "accent-3": #FF1744, 30 | "accent-4": #D50000 31 | ); 32 | 33 | $pink: ( 34 | "base": #e91e63, 35 | "lighten-5": #fce4ec, 36 | "lighten-4": #f8bbd0, 37 | "lighten-3": #f48fb1, 38 | "lighten-2": #f06292, 39 | "lighten-1": #ec407a, 40 | "darken-1": #d81b60, 41 | "darken-2": #c2185b, 42 | "darken-3": #ad1457, 43 | "darken-4": #880e4f, 44 | "accent-1": #ff80ab, 45 | "accent-2": #ff4081, 46 | "accent-3": #f50057, 47 | "accent-4": #c51162 48 | ); 49 | 50 | $purple: ( 51 | "base": #9c27b0, 52 | "lighten-5": #f3e5f5, 53 | "lighten-4": #e1bee7, 54 | "lighten-3": #ce93d8, 55 | "lighten-2": #ba68c8, 56 | "lighten-1": #ab47bc, 57 | "darken-1": #8e24aa, 58 | "darken-2": #7b1fa2, 59 | "darken-3": #6a1b9a, 60 | "darken-4": #4a148c, 61 | "accent-1": #ea80fc, 62 | "accent-2": #e040fb, 63 | "accent-3": #d500f9, 64 | "accent-4": #aa00ff 65 | ); 66 | 67 | $deep-purple: ( 68 | "base": #673ab7, 69 | "lighten-5": #ede7f6, 70 | "lighten-4": #d1c4e9, 71 | "lighten-3": #b39ddb, 72 | "lighten-2": #9575cd, 73 | "lighten-1": #7e57c2, 74 | "darken-1": #5e35b1, 75 | "darken-2": #512da8, 76 | "darken-3": #4527a0, 77 | "darken-4": #311b92, 78 | "accent-1": #b388ff, 79 | "accent-2": #7c4dff, 80 | "accent-3": #651fff, 81 | "accent-4": #6200ea 82 | ); 83 | 84 | $indigo: ( 85 | "base": #3f51b5, 86 | "lighten-5": #e8eaf6, 87 | "lighten-4": #c5cae9, 88 | "lighten-3": #9fa8da, 89 | "lighten-2": #7986cb, 90 | "lighten-1": #5c6bc0, 91 | "darken-1": #3949ab, 92 | "darken-2": #303f9f, 93 | "darken-3": #283593, 94 | "darken-4": #1a237e, 95 | "accent-1": #8c9eff, 96 | "accent-2": #536dfe, 97 | "accent-3": #3d5afe, 98 | "accent-4": #304ffe 99 | ); 100 | 101 | $blue: ( 102 | "base": #2196F3, 103 | "lighten-5": #E3F2FD, 104 | "lighten-4": #BBDEFB, 105 | "lighten-3": #90CAF9, 106 | "lighten-2": #64B5F6, 107 | "lighten-1": #42A5F5, 108 | "darken-1": #1E88E5, 109 | "darken-2": #1976D2, 110 | "darken-3": #1565C0, 111 | "darken-4": #0D47A1, 112 | "accent-1": #82B1FF, 113 | "accent-2": #448AFF, 114 | "accent-3": #2979FF, 115 | "accent-4": #2962FF 116 | ); 117 | 118 | $light-blue: ( 119 | "base": #03a9f4, 120 | "lighten-5": #e1f5fe, 121 | "lighten-4": #b3e5fc, 122 | "lighten-3": #81d4fa, 123 | "lighten-2": #4fc3f7, 124 | "lighten-1": #29b6f6, 125 | "darken-1": #039be5, 126 | "darken-2": #0288d1, 127 | "darken-3": #0277bd, 128 | "darken-4": #01579b, 129 | "accent-1": #80d8ff, 130 | "accent-2": #40c4ff, 131 | "accent-3": #00b0ff, 132 | "accent-4": #0091ea 133 | ); 134 | 135 | $cyan: ( 136 | "base": #00bcd4, 137 | "lighten-5": #e0f7fa, 138 | "lighten-4": #b2ebf2, 139 | "lighten-3": #80deea, 140 | "lighten-2": #4dd0e1, 141 | "lighten-1": #26c6da, 142 | "darken-1": #00acc1, 143 | "darken-2": #0097a7, 144 | "darken-3": #00838f, 145 | "darken-4": #006064, 146 | "accent-1": #84ffff, 147 | "accent-2": #18ffff, 148 | "accent-3": #00e5ff, 149 | "accent-4": #00b8d4 150 | ); 151 | 152 | $teal: ( 153 | "base": #009688, 154 | "lighten-5": #e0f2f1, 155 | "lighten-4": #b2dfdb, 156 | "lighten-3": #80cbc4, 157 | "lighten-2": #4db6ac, 158 | "lighten-1": #26a69a, 159 | "darken-1": #00897b, 160 | "darken-2": #00796b, 161 | "darken-3": #00695c, 162 | "darken-4": #004d40, 163 | "accent-1": #a7ffeb, 164 | "accent-2": #64ffda, 165 | "accent-3": #1de9b6, 166 | "accent-4": #00bfa5 167 | ); 168 | 169 | $green: ( 170 | "base": #4CAF50, 171 | "lighten-5": #E8F5E9, 172 | "lighten-4": #C8E6C9, 173 | "lighten-3": #A5D6A7, 174 | "lighten-2": #81C784, 175 | "lighten-1": #66BB6A, 176 | "darken-1": #43A047, 177 | "darken-2": #388E3C, 178 | "darken-3": #2E7D32, 179 | "darken-4": #1B5E20, 180 | "accent-1": #B9F6CA, 181 | "accent-2": #69F0AE, 182 | "accent-3": #00E676, 183 | "accent-4": #00C853 184 | ); 185 | 186 | $light-green: ( 187 | "base": #8bc34a, 188 | "lighten-5": #f1f8e9, 189 | "lighten-4": #dcedc8, 190 | "lighten-3": #c5e1a5, 191 | "lighten-2": #aed581, 192 | "lighten-1": #9ccc65, 193 | "darken-1": #7cb342, 194 | "darken-2": #689f38, 195 | "darken-3": #558b2f, 196 | "darken-4": #33691e, 197 | "accent-1": #ccff90, 198 | "accent-2": #b2ff59, 199 | "accent-3": #76ff03, 200 | "accent-4": #64dd17 201 | ); 202 | 203 | $lime: ( 204 | "base": #cddc39, 205 | "lighten-5": #f9fbe7, 206 | "lighten-4": #f0f4c3, 207 | "lighten-3": #e6ee9c, 208 | "lighten-2": #dce775, 209 | "lighten-1": #d4e157, 210 | "darken-1": #c0ca33, 211 | "darken-2": #afb42b, 212 | "darken-3": #9e9d24, 213 | "darken-4": #827717, 214 | "accent-1": #f4ff81, 215 | "accent-2": #eeff41, 216 | "accent-3": #c6ff00, 217 | "accent-4": #aeea00 218 | ); 219 | 220 | $yellow: ( 221 | "base": #ffeb3b, 222 | "lighten-5": #fffde7, 223 | "lighten-4": #fff9c4, 224 | "lighten-3": #fff59d, 225 | "lighten-2": #fff176, 226 | "lighten-1": #ffee58, 227 | "darken-1": #fdd835, 228 | "darken-2": #fbc02d, 229 | "darken-3": #f9a825, 230 | "darken-4": #f57f17, 231 | "accent-1": #ffff8d, 232 | "accent-2": #ffff00, 233 | "accent-3": #ffea00, 234 | "accent-4": #ffd600 235 | ); 236 | 237 | $amber: ( 238 | "base": #ffc107, 239 | "lighten-5": #fff8e1, 240 | "lighten-4": #ffecb3, 241 | "lighten-3": #ffe082, 242 | "lighten-2": #ffd54f, 243 | "lighten-1": #ffca28, 244 | "darken-1": #ffb300, 245 | "darken-2": #ffa000, 246 | "darken-3": #ff8f00, 247 | "darken-4": #ff6f00, 248 | "accent-1": #ffe57f, 249 | "accent-2": #ffd740, 250 | "accent-3": #ffc400, 251 | "accent-4": #ffab00 252 | ); 253 | 254 | $orange: ( 255 | "base": #ff9800, 256 | "lighten-5": #fff3e0, 257 | "lighten-4": #ffe0b2, 258 | "lighten-3": #ffcc80, 259 | "lighten-2": #ffb74d, 260 | "lighten-1": #ffa726, 261 | "darken-1": #fb8c00, 262 | "darken-2": #f57c00, 263 | "darken-3": #ef6c00, 264 | "darken-4": #e65100, 265 | "accent-1": #ffd180, 266 | "accent-2": #ffab40, 267 | "accent-3": #ff9100, 268 | "accent-4": #ff6d00 269 | ); 270 | 271 | $deep-orange: ( 272 | "base": #ff5722, 273 | "lighten-5": #fbe9e7, 274 | "lighten-4": #ffccbc, 275 | "lighten-3": #ffab91, 276 | "lighten-2": #ff8a65, 277 | "lighten-1": #ff7043, 278 | "darken-1": #f4511e, 279 | "darken-2": #e64a19, 280 | "darken-3": #d84315, 281 | "darken-4": #bf360c, 282 | "accent-1": #ff9e80, 283 | "accent-2": #ff6e40, 284 | "accent-3": #ff3d00, 285 | "accent-4": #dd2c00 286 | ); 287 | 288 | $brown: ( 289 | "base": #795548, 290 | "lighten-5": #efebe9, 291 | "lighten-4": #d7ccc8, 292 | "lighten-3": #bcaaa4, 293 | "lighten-2": #a1887f, 294 | "lighten-1": #8d6e63, 295 | "darken-1": #6d4c41, 296 | "darken-2": #5d4037, 297 | "darken-3": #4e342e, 298 | "darken-4": #3e2723 299 | ); 300 | 301 | $blue-grey: ( 302 | "base": #607d8b, 303 | "lighten-5": #eceff1, 304 | "lighten-4": #cfd8dc, 305 | "lighten-3": #b0bec5, 306 | "lighten-2": #90a4ae, 307 | "lighten-1": #78909c, 308 | "darken-1": #546e7a, 309 | "darken-2": #455a64, 310 | "darken-3": #37474f, 311 | "darken-4": #263238 312 | ); 313 | 314 | $grey: ( 315 | "base": #9e9e9e, 316 | "lighten-5": #fafafa, 317 | "lighten-4": #f5f5f5, 318 | "lighten-3": #eeeeee, 319 | "lighten-2": #e0e0e0, 320 | "lighten-1": #bdbdbd, 321 | "darken-1": #757575, 322 | "darken-2": #616161, 323 | "darken-3": #424242, 324 | "darken-4": #212121 325 | ); 326 | 327 | $shades: ( 328 | "black": #000000, 329 | "white": #FFFFFF, 330 | "transparent": transparent 331 | ); 332 | 333 | $colors: ( 334 | "materialize-red": $materialize-red, 335 | "red": $red, 336 | "pink": $pink, 337 | "purple": $purple, 338 | "deep-purple": $deep-purple, 339 | "indigo": $indigo, 340 | "blue": $blue, 341 | "light-blue": $light-blue, 342 | "cyan": $cyan, 343 | "teal": $teal, 344 | "green": $green, 345 | "light-green": $light-green, 346 | "lime": $lime, 347 | "yellow": $yellow, 348 | "amber": $amber, 349 | "orange": $orange, 350 | "deep-orange": $deep-orange, 351 | "brown": $brown, 352 | "blue-grey": $blue-grey, 353 | "grey": $grey, 354 | "shades": $shades 355 | ) !default; 356 | 357 | 358 | // usage: color("name_of_color", "type_of_color") 359 | // to avoid to repeating map-get($colors, ...) 360 | 361 | @function color($color, $type) { 362 | @if map-has-key($colors, $color) { 363 | $curr_color: map-get($colors, $color); 364 | @if map-has-key($curr_color, $type) { 365 | @return map-get($curr_color, $type); 366 | } 367 | } 368 | @warn "Unknown `#{$color}` - `#{$type}` in $colors."; 369 | @return null; 370 | } 371 | -------------------------------------------------------------------------------- /renderer/sections/school_timetable_query.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /renderer/scss/_normalize.scss: -------------------------------------------------------------------------------- 1 | /*! normalize.css v7.0.0 | MIT License | github.com/necolas/normalize.css */ 2 | 3 | /* Document 4 | ========================================================================== */ 5 | 6 | /** 7 | * 1. Correct the line height in all browsers. 8 | * 2. Prevent adjustments of font size after orientation changes in 9 | * IE on Windows Phone and in iOS. 10 | */ 11 | 12 | html { 13 | line-height: 1.15; /* 1 */ 14 | -ms-text-size-adjust: 100%; /* 2 */ 15 | -webkit-text-size-adjust: 100%; /* 2 */ 16 | } 17 | 18 | /* Sections 19 | ========================================================================== */ 20 | 21 | /** 22 | * Remove the margin in all browsers (opinionated). 23 | */ 24 | 25 | body { 26 | margin: 0; 27 | } 28 | 29 | /** 30 | * Add the correct display in IE 9-. 31 | */ 32 | 33 | article, 34 | aside, 35 | footer, 36 | header, 37 | nav, 38 | section { 39 | display: block; 40 | } 41 | 42 | /** 43 | * Correct the font size and margin on `h1` elements within `section` and 44 | * `article` contexts in Chrome, Firefox, and Safari. 45 | */ 46 | 47 | h1 { 48 | font-size: 2em; 49 | margin: 0.67em 0; 50 | } 51 | 52 | /* Grouping content 53 | ========================================================================== */ 54 | 55 | /** 56 | * Add the correct display in IE 9-. 57 | * 1. Add the correct display in IE. 58 | */ 59 | 60 | figcaption, 61 | figure, 62 | main { /* 1 */ 63 | display: block; 64 | } 65 | 66 | /** 67 | * Add the correct margin in IE 8. 68 | */ 69 | 70 | figure { 71 | margin: 1em 40px; 72 | } 73 | 74 | /** 75 | * 1. Add the correct box sizing in Firefox. 76 | * 2. Show the overflow in Edge and IE. 77 | */ 78 | 79 | hr { 80 | box-sizing: content-box; /* 1 */ 81 | height: 0; /* 1 */ 82 | overflow: visible; /* 2 */ 83 | } 84 | 85 | /** 86 | * 1. Correct the inheritance and scaling of font size in all browsers. 87 | * 2. Correct the odd `em` font sizing in all browsers. 88 | */ 89 | 90 | pre { 91 | font-family: monospace, monospace; /* 1 */ 92 | font-size: 1em; /* 2 */ 93 | } 94 | 95 | /* Text-level semantics 96 | ========================================================================== */ 97 | 98 | /** 99 | * 1. Remove the gray background on active links in IE 10. 100 | * 2. Remove gaps in links underline in iOS 8+ and Safari 8+. 101 | */ 102 | 103 | a { 104 | background-color: transparent; /* 1 */ 105 | -webkit-text-decoration-skip: objects; /* 2 */ 106 | } 107 | 108 | /** 109 | * 1. Remove the bottom border in Chrome 57- and Firefox 39-. 110 | * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari. 111 | */ 112 | 113 | abbr[title] { 114 | border-bottom: none; /* 1 */ 115 | text-decoration: underline; /* 2 */ 116 | text-decoration: underline dotted; /* 2 */ 117 | } 118 | 119 | /** 120 | * Prevent the duplicate application of `bolder` by the next rule in Safari 6. 121 | */ 122 | 123 | b, 124 | strong { 125 | font-weight: inherit; 126 | } 127 | 128 | /** 129 | * Add the correct font weight in Chrome, Edge, and Safari. 130 | */ 131 | 132 | b, 133 | strong { 134 | font-weight: bolder; 135 | } 136 | 137 | /** 138 | * 1. Correct the inheritance and scaling of font size in all browsers. 139 | * 2. Correct the odd `em` font sizing in all browsers. 140 | */ 141 | 142 | code, 143 | kbd, 144 | samp { 145 | font-family: monospace, monospace; /* 1 */ 146 | font-size: 1em; /* 2 */ 147 | } 148 | 149 | /** 150 | * Add the correct font style in Android 4.3-. 151 | */ 152 | 153 | dfn { 154 | font-style: italic; 155 | } 156 | 157 | /** 158 | * Add the correct background and color in IE 9-. 159 | */ 160 | 161 | mark { 162 | background-color: #ff0; 163 | color: #000; 164 | } 165 | 166 | /** 167 | * Add the correct font size in all browsers. 168 | */ 169 | 170 | small { 171 | font-size: 80%; 172 | } 173 | 174 | /** 175 | * Prevent `sub` and `sup` elements from affecting the line height in 176 | * all browsers. 177 | */ 178 | 179 | sub, 180 | sup { 181 | font-size: 75%; 182 | line-height: 0; 183 | position: relative; 184 | vertical-align: baseline; 185 | } 186 | 187 | sub { 188 | bottom: -0.25em; 189 | } 190 | 191 | sup { 192 | top: -0.5em; 193 | } 194 | 195 | /* Embedded content 196 | ========================================================================== */ 197 | 198 | /** 199 | * Add the correct display in IE 9-. 200 | */ 201 | 202 | audio, 203 | video { 204 | display: inline-block; 205 | } 206 | 207 | /** 208 | * Add the correct display in iOS 4-7. 209 | */ 210 | 211 | audio:not([controls]) { 212 | display: none; 213 | height: 0; 214 | } 215 | 216 | /** 217 | * Remove the border on images inside links in IE 10-. 218 | */ 219 | 220 | img { 221 | border-style: none; 222 | } 223 | 224 | /** 225 | * Hide the overflow in IE. 226 | */ 227 | 228 | svg:not(:root) { 229 | overflow: hidden; 230 | } 231 | 232 | /* Forms 233 | ========================================================================== */ 234 | 235 | /** 236 | * 1. Change the font styles in all browsers (opinionated). 237 | * 2. Remove the margin in Firefox and Safari. 238 | */ 239 | 240 | button, 241 | input, 242 | optgroup, 243 | select, 244 | textarea { 245 | font-family: sans-serif; /* 1 */ 246 | font-size: 100%; /* 1 */ 247 | line-height: 1.15; /* 1 */ 248 | margin: 0; /* 2 */ 249 | } 250 | 251 | /** 252 | * Show the overflow in IE. 253 | * 1. Show the overflow in Edge. 254 | */ 255 | 256 | button, 257 | input { /* 1 */ 258 | overflow: visible; 259 | } 260 | 261 | /** 262 | * Remove the inheritance of text transform in Edge, Firefox, and IE. 263 | * 1. Remove the inheritance of text transform in Firefox. 264 | */ 265 | 266 | button, 267 | select { /* 1 */ 268 | text-transform: none; 269 | } 270 | 271 | /** 272 | * 1. Prevent a WebKit bug where (2) destroys native `audio` and `video` 273 | * controls in Android 4. 274 | * 2. Correct the inability to style clickable types in iOS and Safari. 275 | */ 276 | 277 | button, 278 | html [type="button"], /* 1 */ 279 | [type="reset"], 280 | [type="submit"] { 281 | -webkit-appearance: button; /* 2 */ 282 | } 283 | 284 | /** 285 | * Remove the inner border and padding in Firefox. 286 | */ 287 | 288 | button::-moz-focus-inner, 289 | [type="button"]::-moz-focus-inner, 290 | [type="reset"]::-moz-focus-inner, 291 | [type="submit"]::-moz-focus-inner { 292 | border-style: none; 293 | padding: 0; 294 | } 295 | 296 | /** 297 | * Restore the focus styles unset by the previous rule. 298 | */ 299 | 300 | button:-moz-focusring, 301 | [type="button"]:-moz-focusring, 302 | [type="reset"]:-moz-focusring, 303 | [type="submit"]:-moz-focusring { 304 | outline: 1px dotted ButtonText; 305 | } 306 | 307 | /** 308 | * Correct the padding in Firefox. 309 | */ 310 | 311 | fieldset { 312 | padding: 0.35em 0.75em 0.625em; 313 | } 314 | 315 | /** 316 | * 1. Correct the text wrapping in Edge and IE. 317 | * 2. Correct the color inheritance from `fieldset` elements in IE. 318 | * 3. Remove the padding so developers are not caught out when they zero out 319 | * `fieldset` elements in all browsers. 320 | */ 321 | 322 | legend { 323 | box-sizing: border-box; /* 1 */ 324 | color: inherit; /* 2 */ 325 | display: table; /* 1 */ 326 | max-width: 100%; /* 1 */ 327 | padding: 0; /* 3 */ 328 | white-space: normal; /* 1 */ 329 | } 330 | 331 | /** 332 | * 1. Add the correct display in IE 9-. 333 | * 2. Add the correct vertical alignment in Chrome, Firefox, and Opera. 334 | */ 335 | 336 | progress { 337 | display: inline-block; /* 1 */ 338 | vertical-align: baseline; /* 2 */ 339 | } 340 | 341 | /** 342 | * Remove the default vertical scrollbar in IE. 343 | */ 344 | 345 | textarea { 346 | overflow: auto; 347 | } 348 | 349 | /** 350 | * 1. Add the correct box sizing in IE 10-. 351 | * 2. Remove the padding in IE 10-. 352 | */ 353 | 354 | [type="checkbox"], 355 | [type="radio"] { 356 | box-sizing: border-box; /* 1 */ 357 | padding: 0; /* 2 */ 358 | } 359 | 360 | /** 361 | * Correct the cursor style of increment and decrement buttons in Chrome. 362 | */ 363 | 364 | [type="number"]::-webkit-inner-spin-button, 365 | [type="number"]::-webkit-outer-spin-button { 366 | height: auto; 367 | } 368 | 369 | /** 370 | * 1. Correct the odd appearance in Chrome and Safari. 371 | * 2. Correct the outline style in Safari. 372 | */ 373 | 374 | [type="search"] { 375 | -webkit-appearance: textfield; /* 1 */ 376 | outline-offset: -2px; /* 2 */ 377 | } 378 | 379 | /** 380 | * Remove the inner padding and cancel buttons in Chrome and Safari on macOS. 381 | */ 382 | 383 | [type="search"]::-webkit-search-cancel-button, 384 | [type="search"]::-webkit-search-decoration { 385 | -webkit-appearance: none; 386 | } 387 | 388 | /** 389 | * 1. Correct the inability to style clickable types in iOS and Safari. 390 | * 2. Change font properties to `inherit` in Safari. 391 | */ 392 | 393 | ::-webkit-file-upload-button { 394 | -webkit-appearance: button; /* 1 */ 395 | font: inherit; /* 2 */ 396 | } 397 | 398 | /* Interactive 399 | ========================================================================== */ 400 | 401 | /* 402 | * Add the correct display in IE 9-. 403 | * 1. Add the correct display in Edge, IE, and Firefox. 404 | */ 405 | 406 | details, /* 1 */ 407 | menu { 408 | display: block; 409 | } 410 | 411 | /* 412 | * Add the correct display in all browsers. 413 | */ 414 | 415 | summary { 416 | display: list-item; 417 | } 418 | 419 | /* Scripting 420 | ========================================================================== */ 421 | 422 | /** 423 | * Add the correct display in IE 9-. 424 | */ 425 | 426 | canvas { 427 | display: inline-block; 428 | } 429 | 430 | /** 431 | * Add the correct display in IE. 432 | */ 433 | 434 | template { 435 | display: none; 436 | } 437 | 438 | /* Hidden 439 | ========================================================================== */ 440 | 441 | /** 442 | * Add the correct display in IE 10-. 443 | */ 444 | 445 | [hidden] { 446 | display: none; 447 | } 448 | -------------------------------------------------------------------------------- /renderer/js/yzu_backend.js: -------------------------------------------------------------------------------- 1 | const crypto = require('crypto'); 2 | const request = require("request") 3 | const { default: Axios } = require("axios") 4 | const NodeRSA = require('node-rsa'); 5 | const moment = require("moment") 6 | const fs = require("fs") 7 | 8 | class BackendService { 9 | constructor(sid, spwd) { 10 | this.root_url = "https://portalx.yzu.edu.tw/NewPortal/" 11 | this.AcademicWebAPIurl = "https://portal.yzu.edu.tw/AcademicWebAPI/" 12 | 13 | this.urls = { 14 | getUserAccessTokenUrl: "api/Auth/UserAccessToken", 15 | getRSAAPIKeyByAPPIDUrl: "api/Auth/RSAkeybyAppID", 16 | } 17 | 18 | this.ALLDATA = { 19 | // User Data 20 | "account": "", 21 | "password": "", 22 | // App Data 23 | "AppId": "XamPrismYzu20180206", 24 | "BackUID": "", 25 | "DeviceSerial": "123", // JBAXB7616580PZJ 26 | "APIkey": "YzuAppCall", 27 | "Password": "!@#$_YzuApp_IS5201", 28 | 29 | "PublicKeyXml": "", 30 | 31 | // Header 32 | "Accept": "application/json" 33 | } 34 | 35 | 36 | 37 | this.sid = sid; 38 | this.spwd = spwd; 39 | 40 | this._setSidSpwd(sid, spwd) 41 | 42 | 43 | 44 | this.AcademicWebAPIurl = "https://portal.yzu.edu.tw/AcademicWebAPI/" 45 | this.portalOpenAPIurl = "https://portalx.yzu.edu.tw/OpenData/" 46 | this.portalOpenAPI = { 47 | "News": "api/Open/YzuNews", 48 | "CosList": "api/Open/CosList?year=%s&smtr=%s", 49 | "CosListByTeacher": "api/Open/CosListByTeacher?TeacherName=%s", 50 | } 51 | 52 | 53 | } 54 | 55 | loginService(sid, spwd) { 56 | this._setSidSpwd(sid, spwd) 57 | 58 | yzuService.getRSAKey() 59 | .then((service) => { 60 | return service.encryptData(loginConfig.account, loginConfig.password) 61 | }) 62 | .then((service) => { 63 | return service.getUserAccessToken() 64 | }) 65 | 66 | return true; 67 | } 68 | 69 | _setSidSpwd(sid, spwd) { 70 | this.ALLDATA["account"] = sid; 71 | this.ALLDATA["password"] = spwd; 72 | } 73 | 74 | 75 | 76 | 77 | _getRSAKey() { 78 | var url = "https://portalx.yzu.edu.tw/NewPortal/" + "api/Auth/RSAkeybyAppID" 79 | var ss = this.ALLDATA["APIkey"] + ":" + this.ALLDATA["Password"] 80 | 81 | var payload = { 82 | "AppId": this.ALLDATA["AppId"], 83 | "Content-Type": "application/x-www-form-urlencoded", 84 | } 85 | var headers = { 86 | "Accept": "application/json", 87 | "Authorization": "Basic " + Buffer.from(ss).toString('base64'), 88 | } 89 | 90 | // 存起來 以後就不用再算了 91 | this.ALLDATA["Authorization"] = headers["Authorization"] 92 | this.ALLDATA["Accept"] = headers["Accept"] 93 | 94 | var params = new URLSearchParams() 95 | params.append("AppId", this.ALLDATA["AppId"]) 96 | params.append("Content-Type", "application/x-www-form-urlencoded") 97 | 98 | 99 | var that = this 100 | 101 | return Axios.post(url, params, { 102 | headers: headers 103 | }).then((respones) => { 104 | console.log("---------- RSA") 105 | that.ALLDATA["PublicKeyXml"] = respones.data["RSAkey"] 106 | that.ALLDATA["Modulus"] = respones.data["Modulus"] 107 | that.ALLDATA["Exponent"] = respones.data["Exponent"] 108 | // that.ALLDATA["Modulus"] = toBigIntBE(Buffer.from(respones.data["Modulus"], "base64")) 109 | // that.ALLDATA["Exponent"] = toBigIntBE(Buffer.from(respones.data["Exponent"], "base64")) 110 | 111 | 112 | return new Promise(function (resolve, reject) { 113 | return resolve(that) 114 | }) 115 | 116 | }).catch((error) => { 117 | // console.error(error) 118 | }) 119 | 120 | 121 | } 122 | 123 | _encryptData(account, password) { 124 | 125 | console.log("---------- Login") 126 | 127 | this._setSidSpwd(account, password) 128 | 129 | var key = new NodeRSA() 130 | key.setOptions({ encryptionScheme: "pkcs1" }); 131 | 132 | key.importKey({ 133 | n: Buffer.from(this.ALLDATA["Modulus"], "base64"), 134 | e: 65537, 135 | }, 'components-public'); 136 | 137 | this.ALLDATA["account"] = key.encrypt(Buffer.from(account, "ascii"), "base64") 138 | this.ALLDATA["password"] = key.encrypt(Buffer.from(password, "ascii"), "base64") 139 | 140 | var that = this 141 | return new Promise(function (resolve, reject) { 142 | return resolve(that) 143 | }) 144 | } 145 | 146 | _getUserAccessToken() { 147 | console.log("---------- getUserAccessToken"); 148 | 149 | var url = "https://portalx.yzu.edu.tw/NewPortal/" + "api/Auth/UserAccessToken" 150 | 151 | var payload = new URLSearchParams() 152 | payload.append("AppId", this.ALLDATA["AppId"]) 153 | payload.append("account", this.ALLDATA["account"]) 154 | payload.append("password", this.ALLDATA["password"]) 155 | payload.append("BackUID", this.ALLDATA["BackUID"]) 156 | payload.append("DeviceSerial", this.ALLDATA["DeviceSerial"]) 157 | 158 | 159 | var headers = { 160 | "Accept": this.ALLDATA["Accept"], 161 | "Authorization": this.ALLDATA["Authorization"] 162 | } 163 | 164 | 165 | var that = this 166 | 167 | return Axios.post(url, payload, { 168 | headers: headers 169 | }).then((response) => { 170 | 171 | if (response.data.Result.includes("失敗")) { 172 | return Promise.reject(new Error("解密失敗")) 173 | } 174 | 175 | this.login_infomation = response.data; 176 | this.login_infomation["dept"] = response.data["UserStatus"].split('_')[2] 177 | 178 | this.ALLDATA["Token"] = response.data["Token"] 179 | this.ALLDATA["UserStatus"] = response.data["UserStatus"] 180 | 181 | 182 | var that = this; 183 | // 繼續 promise 的 chain 184 | return new Promise(function (resolve, reject) { 185 | return resolve(that) 186 | }) 187 | 188 | }) 189 | 190 | } 191 | 192 | _getLoginAccount() { 193 | var url = "https://isdna1.yzu.edu.tw/StdSelWebAPI/api/SelCos/Get_LoginAccount_Str" 194 | 195 | var payload = new URLSearchParams() 196 | payload.append("sToken", this.ALLDATA["Token"]) 197 | 198 | 199 | var headers = { 200 | "Accept": this.ALLDATA["Accept"], 201 | // "Authorization": this.ALLDATA["Authorization"] 202 | } 203 | 204 | 205 | return Axios.post(url, payload, { 206 | headers: headers 207 | }).then((response) => { 208 | 209 | console.log(response) 210 | 211 | 212 | 213 | var that = this; 214 | // 繼續 promise 的 chain 215 | return new Promise(function (resolve, reject) { 216 | return resolve(that) 217 | }) 218 | 219 | }) 220 | } 221 | 222 | _getAppLoginccount() { 223 | var url = "https://portal.yzu.edu.tw/StdWebAPI/api/CheckAppAccessToken20190216/GetAppAccount" 224 | 225 | var payload = new URLSearchParams() 226 | payload.append("Token", this.ALLDATA["Token"]) 227 | payload.append("Lang", "zh") 228 | 229 | 230 | var headers = { 231 | "Accept": this.ALLDATA["Accept"], 232 | // "Authorization": this.ALLDATA["Authorization"] 233 | } 234 | 235 | var that = this; 236 | 237 | return Axios.post(url, payload, { 238 | headers: headers 239 | }).then((response) => { 240 | 241 | console.log(response.data) 242 | that.std_account_infomation = response.data 243 | 244 | 245 | // 繼續 promise 的 chain 246 | return new Promise(function (resolve, reject) { 247 | return resolve(that) 248 | }) 249 | 250 | }) 251 | } 252 | 253 | 254 | getCourseSchedule(year, smtr) { 255 | var url = "https://portal.yzu.edu.tw/AcademicWebAPI/api/Cos/Get_Course_Schedule" 256 | 257 | var payload = new URLSearchParams() 258 | payload.append("token", this.ALLDATA["Token"]) 259 | payload.append("year", year) 260 | payload.append("smtr", smtr) 261 | payload.append("ShowLang", "zh") 262 | 263 | var headers = { 264 | "Accept": this.ALLDATA["Accept"], 265 | } 266 | 267 | return Axios.post(url, payload, { headers: headers }).then((response) => { 268 | console.log(response.data) 269 | 270 | var that = this; 271 | // 繼續 promise 的 chain 272 | return new Promise(function (resolve, reject) { 273 | return resolve(that) 274 | }) 275 | 276 | }) 277 | } 278 | 279 | 280 | getNotifyList() { 281 | var url = "https://portalx.yzu.edu.tw/NewPortal/api/FCM/NotifyList" 282 | 283 | var payload = new URLSearchParams() 284 | payload.append("Token", this.ALLDATA["Token"]) 285 | payload.append("FCMToken", "") 286 | 287 | var headers = { 288 | "Accept": this.ALLDATA["Accept"], 289 | } 290 | 291 | return Axios.post(url, payload, { headers: headers }).then((response) => { 292 | console.log("Notify: ", response.data) 293 | this.notify_list = [] 294 | var length_to_truncate = 20; 295 | // 針對 notify item 做處理 296 | response.data.forEach(element => { 297 | // 截短 Title 298 | if (element.Title.length > length_to_truncate) { 299 | element.Title = element.Title.substring(0, length_to_truncate) + "..."; 300 | } else { 301 | element.Title = element.Title; 302 | } 303 | 304 | // 使用 moment 轉換格式 305 | element.SendDate = moment(element.SendDate).format('YYYY/MM/DD'); 306 | this.notify_list.push(element); 307 | }); 308 | 309 | // this.notify_list = response.data; 310 | /** 311 | * Title 312 | * Body 313 | * ETitle 314 | * EBody 315 | * 316 | * NotifyType 317 | * PostID 318 | * SendDate 319 | */ 320 | 321 | var that = this; 322 | // 繼續 promise 的 chain 323 | return new Promise(function (resolve, reject) { 324 | return resolve(that) 325 | }) 326 | 327 | }) 328 | } 329 | 330 | 331 | /** 332 | * 得到某一學年某學期修的課程列表 333 | * @param {string} year 學年,ex: 108, 107 334 | * @param {string} smtr 學期,ex: 1, 2 335 | */ 336 | getCourseListFromYZUApi(year, smtr) { 337 | console.log("Calling: " + this.portalOpenAPIurl + this.portalOpenAPI["CosList"]); 338 | 339 | var url = this.portalOpenAPIurl + "/api/Open/CosList?year=" + year + "&smtr=" + smtr 340 | console.log(year, smtr); 341 | console.log(url); 342 | 343 | return new Promise(function (resolve, reject) { 344 | request.get(url, function (err, response, body) { 345 | if (!err && response.statusCode == 200) { 346 | var dept_list = []; // 所有科系名稱 347 | 348 | var data = JSON.parse(body) 349 | data.forEach(function(datum, index, theArray) { 350 | dept_list.indexOf(datum["dept_name"]) === -1 ? dept_list.push(datum["dept_name"].trim()): ""; 351 | theArray[index].smtr = datum["smtr"].trim(); 352 | 353 | 354 | var times = datum["WeekandRoom"].split(",") 355 | var r = RegExp("([0-9]{3})\(([0-9a-zA-Z]*)\)", "g"); 356 | 357 | var datumTime = []; 358 | 359 | times.forEach((time)=>{ 360 | if(time==""){ 361 | return; 362 | } 363 | 364 | var info = time.match(r); 365 | 366 | if(info==null){ 367 | datum["time"] = "無課程資料"; 368 | datum["room"] = "無課程資料"; 369 | }else if(info.length==1){ 370 | datum["time"] = info[0]; 371 | datum["room"] = "無教室位置"; 372 | datumTime.push(info[0]) 373 | }else{ 374 | datum["time"] = info[0]; 375 | datum["room"] = info[1]; 376 | datumTime.push(info[0]) 377 | } 378 | }) 379 | 380 | if(datumTime.length > 0){ 381 | datum["time"] = datumTime.join(",") 382 | } 383 | 384 | 385 | theArray[index].hashid = crypto.createHash('md5').update(JSON.stringify(datum)).digest('hex'); 386 | }); 387 | 388 | return resolve({ 389 | course_list: data, 390 | dept_list: dept_list 391 | }) 392 | } 393 | }) 394 | }) 395 | } 396 | 397 | 398 | 399 | 400 | 401 | 402 | selCourseInline(course) { 403 | 404 | let settings = JSON.parse(fs.readFileSync('settings.json')) 405 | 406 | var url = "https://isdna1.yzu.edu.tw/StdSelWebAPI/api/SelCos/Get_AddCosCheck_Str" 407 | 408 | var payload = new URLSearchParams() 409 | payload.append("sYear", course["year"]) 410 | payload.append("sSmtr", course["smtr"]) 411 | payload.append("sStage", "1") 412 | 413 | payload.append("sCos_id", course["cos_id"]) 414 | payload.append("sCos_class", course["cos_class"]) 415 | payload.append("sCosTerm_id", "1") 416 | payload.append("sAcadType", "Y") 417 | payload.append("sIPAddr", "APP") 418 | payload.append("sApi", "Y") 419 | payload.append("sBackDoor", "0") 420 | payload.append("sLanguage", "TW") 421 | payload.append("sToken", settings["token"]) 422 | 423 | // SelCos,CS572,A,1,D,3,Y,Chinese,CS572,A,3 軟體工程 424 | // { 425 | // "sYear": "108", 426 | // "sSmtr": "2", 427 | // "sStage": "2", 428 | // "sCos_id": "CS554", 429 | // "sCos_class": "A", 430 | // "sCosTerm_id": "1", 431 | // "sAcadType": "Y", 432 | // "sIPAddr": "APP", 433 | // "sApi": "Y", 434 | // "sBackDoor": "0", 435 | // "sLanguage": "TW", 436 | // "sToken": ALLDATA["Token"], 437 | // } 438 | 439 | var headers = { 440 | "Accept": this.ALLDATA["Accept"], 441 | } 442 | 443 | return Axios.post(url, payload, { 444 | headers: headers 445 | }).then((response) => { 446 | // console.log(response); 447 | return new Promise(function (resolve, reject) { 448 | return resolve(response) 449 | }) 450 | 451 | }) 452 | } 453 | 454 | } 455 | 456 | 457 | 458 | 459 | 460 | module.exports = { BackendService }; -------------------------------------------------------------------------------- /renderer/css/wannaclass.css.map: -------------------------------------------------------------------------------- 1 | { 2 | "version": 3, 3 | "mappings": "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", 4 | "sources": [ 5 | "../scss/wannaclass.scss", 6 | "../scss/_color-variables.scss", 7 | "../scss/_variables.scss", 8 | "../scss/_normalize.scss", 9 | "../scss/_typography.scss", 10 | "../scss/materializecss/_tapTarget.scss", 11 | "../scss/materializecss/_modal.scss", 12 | "../scss/_global.scss", 13 | "../scss/_login-page.scss", 14 | "../scss/_content-page.scss", 15 | "../scss/_sidebar.scss", 16 | "../scss/_hover.scss" 17 | ], 18 | "names": [], 19 | "file": "wannaclass.css" 20 | } -------------------------------------------------------------------------------- /assets/undraw_programming_2svr.svg: -------------------------------------------------------------------------------- 1 | programming -------------------------------------------------------------------------------- /renderer/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Wanna Class Application 8 | 9 | 10 | 11 | 12 | 13 | 14 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 |
59 | 60 | 61 | 65 | 66 | 67 | 68 | 112 | 113 | 114 | 115 |
116 | 148 | 149 |
150 | 151 |
152 |
153 |

{{ greetings }} {{ std_account_infomation.CName }}, 今天想要來點什麼學分?

154 |
155 | 156 |
157 |
158 |
159 | {{notify.Title}}{{ notify.SendDate }} 160 |
161 | 169 |
170 |
171 | 172 |
173 |
174 |
175 | 176 | 177 |
178 |

課程查詢 {{ }}

179 | 180 |
181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 |
    189 |
  • 190 |
  • 191 |
  • 192 |
  • 193 |
194 | 195 |
196 |
197 |
198 |
199 | 200 |
201 |

系所查詢

202 |
203 |
204 | 205 | 209 |
210 |
211 | 212 | 218 |
219 | 220 |
221 | 222 | 227 |
228 | 229 |
230 |
231 | 232 | 233 |
234 |

課程關鍵字查詢

235 |
236 |
237 | 238 | 242 |
243 |
244 | 245 | 251 |
252 |
253 |
254 |
255 | 256 | 258 |
259 |
260 |
261 | 262 | 263 |
264 |

教師姓名

265 |
266 |
267 | 268 | 272 |
273 |
274 | 275 | 281 |
282 |
283 |
284 |
285 | 286 | 288 |
289 |
290 |
291 | 292 | 293 |
294 |

時間查詢

295 |
296 |
297 | 298 | 302 |
303 |
304 | 305 | 311 |
312 |
313 |
314 |
315 | 316 | 327 |
328 |
329 | 330 | 347 |
348 |
349 |
350 |
351 |
352 | 355 | 356 |
357 | 358 | 359 | 360 | 361 | 362 |
363 | 366 |
367 |

{{ modalCourse.name }}

368 |
369 |
370 |

由{{ modalCourse.teacher_name 371 | }}教授教導,為系上的{{modalCourse.cos_type_name}}課程之一,上課教室位於{{modalCourse.room}},學分數為{{modalCourse.credit}}。 372 |

373 |
374 |
375 | 376 | 377 |
378 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 395 | 396 | 397 | 398 | 399 | 400 | 402 | 403 | 404 | 405 |
課程名稱授課教師課程類型學分數學系加入選課名單
{{course.name}}{{course.teacher_name}}{{course.cos_type_name}}{{course.credit}}{{course.dept_name}}加入選課清單
406 |
407 |
408 |
409 | 410 | 411 |
412 |

選課任務列表

413 | 414 | 415 |
416 |
417 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 |
Task ID學系課程名稱課程類型學分數選課狀態
{{task.id}}{{task.dept_name}}{{task.name}}{{task.cos_type_name}}{{task.credit}}{{ status(task.status) }}
442 |
443 |
444 |
445 | 446 | 447 |
448 |
449 | 450 |
451 |
452 |
個人資訊
453 |
454 |
455 | 456 |
457 | 458 | 461 |
462 | 463 |
464 | 465 | 468 |
469 | 470 |
471 |
472 |
473 |
474 |
Settings
475 |
476 |
477 |
478 | 480 | 482 | 483 | 484 | 491 |
492 |
493 |
494 | 495 |
496 |
497 |
498 |
499 |
500 |
501 | 502 | 503 | 504 | 543 | 544 |
545 | 546 | 547 |
548 | 549 | 550 | 551 | 552 | 553 | 554 | 555 | 556 | 557 | --------------------------------------------------------------------------------