Compare commits

...

7 commits

11 changed files with 687 additions and 141 deletions

168
package-lock.json generated
View file

@ -8,6 +8,8 @@
"name": "router-ui-frontend", "name": "router-ui-frontend",
"version": "0.0.0", "version": "0.0.0",
"dependencies": { "dependencies": {
"axios": "^1.7.7",
"axios": "^1.7.7",
"path": "^0.12.7", "path": "^0.12.7",
"vue": "^3.4.37", "vue": "^3.4.37",
"vue-router": "^4.4.3" "vue-router": "^4.4.3"
@ -16,7 +18,7 @@
"@types/node": "^22.5.1", "@types/node": "^22.5.1",
"@vitejs/plugin-vue": "^5.1.3", "@vitejs/plugin-vue": "^5.1.3",
"typescript": "^5.5.3", "typescript": "^5.5.3",
"vite": "^5.4.1", "vite": "^5.4.3",
"vite-svg-loader": "^5.1.0", "vite-svg-loader": "^5.1.0",
"vue-tsc": "^2.0.29" "vue-tsc": "^2.0.29"
} }
@ -838,6 +840,36 @@
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.38.tgz", "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.38.tgz",
"integrity": "sha512-q0xCiLkuWWQLzVrecPb0RMsNWyxICOjPrcrwxTUEHb1fsnvni4dcuyG7RT/Ie7VPTvnjzIaWzRMUBsrqNj/hhw==" "integrity": "sha512-q0xCiLkuWWQLzVrecPb0RMsNWyxICOjPrcrwxTUEHb1fsnvni4dcuyG7RT/Ie7VPTvnjzIaWzRMUBsrqNj/hhw=="
}, },
"node_modules/asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
},
"node_modules/axios": {
"version": "1.7.7",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.7.7.tgz",
"integrity": "sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==",
"dependencies": {
"follow-redirects": "^1.15.6",
"form-data": "^4.0.0",
"proxy-from-env": "^1.1.0"
}
},
"node_modules/asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
},
"node_modules/axios": {
"version": "1.7.7",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.7.7.tgz",
"integrity": "sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==",
"dependencies": {
"follow-redirects": "^1.15.6",
"form-data": "^4.0.0",
"proxy-from-env": "^1.1.0"
}
},
"node_modules/balanced-match": { "node_modules/balanced-match": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
@ -859,6 +891,28 @@
"balanced-match": "^1.0.0" "balanced-match": "^1.0.0"
} }
}, },
"node_modules/combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"dependencies": {
"delayed-stream": "~1.0.0"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"dependencies": {
"delayed-stream": "~1.0.0"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/commander": { "node_modules/commander": {
"version": "7.2.0", "version": "7.2.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz",
@ -959,6 +1013,22 @@
"integrity": "sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==", "integrity": "sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==",
"dev": true "dev": true
}, },
"node_modules/delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/dom-serializer": { "node_modules/dom-serializer": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
@ -1068,6 +1138,38 @@
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
"integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==" "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="
}, },
"node_modules/follow-redirects": {
"version": "1.15.8",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.8.tgz",
"integrity": "sha512-xgrmBhBToVKay1q2Tao5LI26B83UhrB/vM1avwVSDzt8rx3rO6AizBAaF46EgksTVr+rFTQaqZZ9MVBfUe4nig==",
"funding": [
{
"type": "individual",
"url": "https://github.com/sponsors/RubenVerborgh"
}
],
"engines": {
"node": ">=4.0"
},
"peerDependenciesMeta": {
"debug": {
"optional": true
}
}
},
"node_modules/form-data": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
"dependencies": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"mime-types": "^2.1.12"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/fsevents": { "node_modules/fsevents": {
"version": "2.3.3", "version": "2.3.3",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
@ -1110,6 +1212,44 @@
"integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==",
"dev": true "dev": true
}, },
"node_modules/mime-db": {
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/mime-types": {
"version": "2.1.35",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"dependencies": {
"mime-db": "1.52.0"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/mime-db": {
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/mime-types": {
"version": "2.1.35",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"dependencies": {
"mime-db": "1.52.0"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/minimatch": { "node_modules/minimatch": {
"version": "9.0.5", "version": "9.0.5",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
@ -1181,9 +1321,9 @@
"integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==" "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew=="
}, },
"node_modules/postcss": { "node_modules/postcss": {
"version": "8.4.41", "version": "8.4.45",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.41.tgz", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.45.tgz",
"integrity": "sha512-TesUflQ0WKZqAvg52PWL6kHgLKP6xB6heTOdoYM0Wt2UHyxNa4K25EZZMgKns3BH1RLVbZCREPpLY0rhnNoHVQ==", "integrity": "sha512-7KTLTdzdZZYscUc65XmjFiB73vBhBfbPztCYdUNvlaso9PrzjzcmjqBPR0lNGkcVlcO4BjiO5rK/qNz+XAen1Q==",
"funding": [ "funding": [
{ {
"type": "opencollective", "type": "opencollective",
@ -1215,6 +1355,16 @@
"node": ">= 0.6.0" "node": ">= 0.6.0"
} }
}, },
"node_modules/proxy-from-env": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
},
"node_modules/proxy-from-env": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
},
"node_modules/rollup": { "node_modules/rollup": {
"version": "4.21.0", "version": "4.21.0",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.21.0.tgz", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.21.0.tgz",
@ -1331,14 +1481,14 @@
} }
}, },
"node_modules/vite": { "node_modules/vite": {
"version": "5.4.1", "version": "5.4.3",
"resolved": "https://registry.npmjs.org/vite/-/vite-5.4.1.tgz", "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.3.tgz",
"integrity": "sha512-1oE6yuNXssjrZdblI9AfBbHCC41nnyoVoEZxQnID6yvQZAFBzxxkqoFLtHUMkYunL8hwOLEjgTuxpkRxvba3kA==", "integrity": "sha512-IH+nl64eq9lJjFqU+/yrRnrHPVTlgy42/+IzbOdaFDVlyLgI/wDlf+FCobXLX1cT0X5+7LMyH1mIy2xJdLfo8Q==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"esbuild": "^0.21.3", "esbuild": "^0.21.3",
"postcss": "^8.4.41", "postcss": "^8.4.43",
"rollup": "^4.13.0" "rollup": "^4.20.0"
}, },
"bin": { "bin": {
"vite": "bin/vite.js" "vite": "bin/vite.js"

View file

@ -9,6 +9,7 @@
"preview": "vite preview" "preview": "vite preview"
}, },
"dependencies": { "dependencies": {
"axios": "^1.7.7",
"path": "^0.12.7", "path": "^0.12.7",
"vue": "^3.4.37", "vue": "^3.4.37",
"vue-router": "^4.4.3" "vue-router": "^4.4.3"
@ -17,7 +18,7 @@
"@types/node": "^22.5.1", "@types/node": "^22.5.1",
"@vitejs/plugin-vue": "^5.1.3", "@vitejs/plugin-vue": "^5.1.3",
"typescript": "^5.5.3", "typescript": "^5.5.3",
"vite": "^5.4.1", "vite": "^5.4.3",
"vite-svg-loader": "^5.1.0", "vite-svg-loader": "^5.1.0",
"vue-tsc": "^2.0.29" "vue-tsc": "^2.0.29"
} }

View file

@ -0,0 +1,40 @@
<script setup lang="ts">
import { useRoute } from 'vue-router';
import { watch, shallowRef } from 'vue';
const {excludedPages} = defineProps<{
excludedPages?: string[]
}>();
const route = useRoute();
let showActionFooter = shallowRef(true);
const checkExluded = (path: string) => {
if(excludedPages){
for(let i = 0; i < excludedPages.length; i++) {
if(excludedPages[i] === path) {
showActionFooter.value = false;
break;
} else {
showActionFooter.value = true;
}
}
}
}
checkExluded(route.path);
watch(() => route.path, (newPath) => {
checkExluded(newPath);
});
</script>
<template>
<footer id="footer" v-if="showActionFooter">
<h2>Save Changes?</h2>
<div>
<button class="apply">Apply</button>
<button>Cancel</button>
</div>
</footer>
</template>

0
src/components/Popup.vue Normal file
View file

View file

@ -1,5 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import Navbar from '@/components/Navbar.vue'; import Navbar from '@/components/Navbar.vue';
import ActionFooter from '@/components/ActionFooter.vue'
interface NavbarItem { interface NavbarItem {
name: string; name: string;
@ -31,6 +32,7 @@
</div> </div>
<div id="basicComponents"> <div id="basicComponents">
<RouterView/> <RouterView/>
<ActionFooter :excludedPages="['/basic']"/>
</div> </div>
</div> </div>
</template> </template>

View file

@ -1,62 +1,113 @@
<script lang="ts" setup>
import { shallowRef } from 'vue'
const pageTitle="Internet Setup"
interface sectionsType {
title: string,
ID: string,
forms: {
name: string,
class: string,
option: string,
label: string
}[]
}
const sections = shallowRef<sectionsType[]>([]);
sections.value = [
{
title: "Does your internet require a login?",
ID: "internetSetupLogin",
forms: [
{
name: "internetLoginOption",
class: "selectOption",
option: "radio",
label: "Yes"
},
{
name: "internetLoginOption",
class: "selectOption",
option: "radio",
label: "No"
}
]
},
{
title: "Internet IP Address",
ID: "internetSetupIP",
forms: [
{
name: "internetIPOption",
class: "selectOption",
option: "radio",
label: "Dynamic IP from ISP"
},
{
name: "internetIPOption",
class: "selectOption",
option: "radio",
label: "Static IP from ISP"
}
]
},
{
title: "DNS (Domain Name Server) Address",
ID: "internetSetupDNS",
forms: [
{
name: "internetDNSOption",
class: "selectOption",
option: "radio",
label: "Automatic DNS from ISP"
},
{
name: "internetDNSOption",
class: "selectOption",
option: "radio",
label: "Select DNS Servers"
}
]
}, {
title: "Router MAC Address",
ID: "internetSetupMAC",
forms: [
{
name: "internetMACOption",
class: "selectOption",
option: "radio",
label: "Default Address"
},
{
name: "internetMACOption",
class: "selectOption",
option: "radio",
label: "Computer MAC Address"
},
{
name: "internetMACOption",
class: "selectOption",
option: "radio",
label: "Specific MAC Adress"
}
]
}
]
</script>
<template> <template>
<div id="internetSetupComponent"> <div id="internetSetupComponent">
<h2 class="title">Internet Setup</h2> <h2 class="title">{{ pageTitle }}</h2>
<section id="internetSetupLogin"> <section v-for="section in sections" :id="section.ID" :key="section.ID">
<h3>Does your internet connection require a login?</h3> <h3>{{ section.title }}</h3>
<!-- There will be no input (keyboard) for the time being because that requires backend to handle. -->
<form> <form>
<label> <label :class="form.class" v-for="(form, index) in section.forms">
<input type="radio" name="internetLoginOption" value="1"> <input :type="form.option" :name="form.name" :value="index + 1" :key="form.label">
<p>Yes</p> {{ form.label }}
</label>
<label>
<input type="radio" name="internetLoginOption" value="2">
<p>No</p>
</label>
</form>
</section>
<section id="internetSetupIP">
<h3>Internet IP Address</h3>
<form>
<label>
<input type="radio" name="internetIPOption" value="1">
<p>Dynamic IP from ISP</p>
</label>
<label>
<input type="radio" name="internetIPOption" value="2">
<p>Static IP from ISP</p>
</label>
</form>
</section>
<section>
<h3>DNS (Domain Name Server) Address</h3>
<form>
<label>
<input type="radio" name="internetDNSOption" value="1">
<p>Automatic DNS from ISP</p>
</label>
<label>
<input type="radio" name="internetDNSOption" value="2">
<p>Select DNS Servers</p>
</label>
</form>
</section>
<section>
<h3>Router MAC Address</h3>
<form>
<label>
<input type="radio" name="internetMACOption" value="1">
<p>Default Address</p>
</label>
<label>
<input type="radio" name="internetMACOption" value="2">
<p>Computer MAC Address</p>
</label>
<label>
<input type="radio" name="internetMACOption" value="2">
<p>Specific MAC Adress</p>
</label> </label>
</form> </form>
<div class="seperator"></div>
</section> </section>
</div> </div>
</template> </template>

View file

@ -1,4 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { shallowRef, onMounted } from 'vue';
import axios from 'axios';
import internetIcon from '@/assets/overviewSvgs/Internet.svg' import internetIcon from '@/assets/overviewSvgs/Internet.svg'
import wifiIcon from '@/assets/overviewSvgs/Wifi.svg' import wifiIcon from '@/assets/overviewSvgs/Wifi.svg'
import devicesIcon from '@/assets/overviewSvgs/Devices.svg' import devicesIcon from '@/assets/overviewSvgs/Devices.svg'
@ -7,6 +10,7 @@
import guestNetworkIcon from '@/assets/overviewSvgs/GuestNetwork.svg' import guestNetworkIcon from '@/assets/overviewSvgs/GuestNetwork.svg'
interface statusColorsType { interface statusColorsType {
[key: string]: string;
goodStatus: string; goodStatus: string;
warningStatus: string; warningStatus: string;
badStatus: string; badStatus: string;
@ -26,56 +30,88 @@
statusMessage: string; statusMessage: string;
} }
const overviewItems: overviewItemsType[] = [ const backendOnline = shallowRef<boolean>(true);
{
name: "Internet", const overviewItems = shallowRef<overviewItemsType[]>([]);
link: "/basic/internet",
icon: internetIcon, const internetMode = shallowRef<string | null>(null);
statusColor: statusColors.goodStatus, const wifiMode5Ghz = shallowRef<string | null>(null);
statusMessage: "Online: LAN4", const wifiMode2Ghz = shallowRef<number | null>(null);
}, const devices = shallowRef<string | null>(null);
{ const fileShare = shallowRef<string | null>(null);
name: "Wifi", const qos = shallowRef<string | null>(null);
link: "/basic/wireless", const guestNetwork = shallowRef<string | null>(null);
icon: wifiIcon,
statusColor: statusColors.warningStatus, const fetchOverviewItems = async () => {
statusMessage: "5Ghz: On | 2.4Ghz: Off", try {
}, const response = await axios.get('http://localhost:8080/overviewItems');
{
name: "Devices", internetMode.value = response.data.internetMode;
link: "/basic/devices", wifiMode5Ghz.value = response.data.wifiMode5Ghz;
icon: devicesIcon, wifiMode2Ghz.value = response.data.wifiMode2Ghz;
statusColor: null, devices.value = response.data.devices;
statusMessage: "Online: 0", fileShare.value = response.data.fileShare;
}, qos.value = response.data.qos;
{ guestNetwork.value = response.data.guestNetwork
name: "File Sharing",
link: "/basic/fileshare", overviewItems.value = [
icon: fileSharingIcon, {
statusColor: statusColors.badStatus, name: "Internet",
statusMessage: "Offline", link: "/basic/internet",
}, icon: internetIcon,
{ statusColor: statusColors.goodStatus,
name: "QoS", statusMessage: `Online: ${internetMode.value}`,
link: "/basic/qos", },
icon: qosIcon, {
statusColor: statusColors.goodStatus, name: "Wifi",
statusMessage: "Online", link: "/basic/wireless",
}, icon: wifiIcon,
{ statusColor: statusColors.warningStatus,
name: "Guest Network", statusMessage: `5Ghz: ${wifiMode5Ghz.value} | 2.4Ghz: ${wifiMode2Ghz.value}`,
link: "/basic/guestnetwork", },
icon: guestNetworkIcon, {
statusColor: statusColors.badStatus, name: "Devices",
statusMessage: "Offline", link: "/basic/devices",
icon: devicesIcon,
statusColor: null,
statusMessage: `Online: ${devices.value}`,
},
{
name: "File Sharing",
link: "/basic/fileshare",
icon: fileSharingIcon,
statusColor: statusColors.badStatus,
statusMessage: `${fileShare.value}`,
},
{
name: "QoS",
link: "/basic/qos",
icon: qosIcon,
statusColor: statusColors.goodStatus,
statusMessage: `${qos.value}`,
},
{
name: "Guest Network",
link: "/basic/guestnetwork",
icon: guestNetworkIcon,
statusColor: statusColors.badStatus,
statusMessage: `${guestNetwork}`,
}
];
} catch (error) {
return backendOnline.value = false;
} }
] };
onMounted(() => {
fetchOverviewItems();
})
</script> </script>
<template> <template>
<div id="overviewComponent"> <div id="overviewComponent">
<h2 class="title">Overview</h2> <h2 class="title">Overview</h2>
<ul> <ul v-if="backendOnline">
<RouterLink :to="overviewItem.link" v-for="overviewItem in overviewItems"> <RouterLink :to="overviewItem.link" v-for="overviewItem in overviewItems">
<li> <li>
<component :is="overviewItem.icon"/> <component :is="overviewItem.icon"/>
@ -84,6 +120,7 @@
</li> </li>
</RouterLink> </RouterLink>
</ul> </ul>
<p class="error" v-else>Backend offline or not available, please try again later.</p>
</div> </div>
</template> </template>

View file

@ -1,6 +1,169 @@
<template> <template>
<div> <div id="wirelessSettingsComponent">
<h2 class="title">Wireless Settings</h2> <h2 class="title">Wireless Settings</h2>
<!-- Backend required to finish -->
<section>
<h3>General Setup</h3>
<form>
<label class="selectOption">
<input type="checkbox"/>
Enable AX (OFDMA Feature)
</label>
<label class="selectOption">
<input type="checkbox"/>
Enable OFDMA (2.4Ghz)
</label>
<label class="selectOption">
<input type="checkbox"/>
Enable OFDMA (5Ghz)
</label>
<label class="selectOption">
<input type="checkbox"/>
Enable automatic 2.4Ghz & 5Ghz switching
</label>
</form>
</section>
<div class="seperator"></div>
<section>
<h3>Wireless 2.4GHz</h3>
<form>
<label class="selectOption">
<input type="checkbox">
Enable SSID Broadcast
</label>
<label class="selectOption">
<input type="checkbox">
Enable 20/40 MHz Coexistence
</label>
<label class="inputName">
<input type="text" name="wirelessName" value="SomeRandomNetwork"/>
Name (SSID)
</label>
<label class="dropdownBox">
<select>
<option valie="Auto">Auto</option>
<option value="01">01</option>
<option value="02">02</option>
<option value="03">03</option>
<option value="04">04</option>
<option value="05">05</option>
<option value="06">06</option>
<option value="07">07</option>
<option value="08">08</option>
<option value="09">09</option>
<option value="10">10</option>
<option value="11">11</option>
</select>
Channel
</label>
<label class="dropdownBox">
<select>
<option value="54">54 Mbps</option>
<option value="289">289 Mbps</option>
<option value="600">600 Mbps</option>
</select>
Mode
</label>
<label class="subSelect">
<label class="selectOption">
<input type="radio" name="securityOption" value="1">
None
</label>
<label class="selectOption">
<input type="radio" name="securityOption" value="2">
WPA2-personal [AES]
</label>
<label class="selectOption">
<input type="radio" name="securityOption" value="3">
WPA-Personal [TKIP] + WPA2-Personal [AES]
</label>
<label class="selectOption">
<input type="radio" name="securityOption" value="4">
WPA3-Personal [SAE]
</label>
<label class="selectOption">
<input type="radio" name="securityOption" value="5">
WPA2-personal [AES] + WPA3-Personal
</label>
Security Options
</label>
<label class="inputName">
<input type="password" name="wirelessName" value="SomeRandomPassword"/>
Password (Network)
</label>
</form>
</section>
<div class="seperator"></div>
<section>
<h3>Wireless 5GHz</h3>
<form>
<label class="selectOption">
<input type="checkbox">
Enable SSID Broadcast
</label>
<label class="selectOption">
<input type="checkbox">
Enable 20/40 MHz Coexistence
</label>
<label class="inputName">
<input type="text" name="wirelessName" value="SomeRandomNetwork"/>
Name (SSID)
</label>
<label class="dropdownBox">
<select>
<option valie="Auto">Auto</option>
<option value="01">01</option>
<option value="02">02</option>
<option value="03">03</option>
<option value="04">04</option>
<option value="05">05</option>
<option value="06">06</option>
<option value="07">07</option>
<option value="08">08</option>
<option value="09">09</option>
<option value="10">10</option>
<option value="11">11</option>
</select>
Channel
</label>
<label class="dropdownBox">
<select>
<option value="54">54 Mbps</option>
<option value="289">289 Mbps</option>
<option value="600">600 Mbps</option>
</select>
Mode
</label>
<label class="subSelect">
<label class="selectOption">
<input type="radio" name="securityOption" value="1">
None
</label>
<label class="selectOption">
<input type="radio" name="securityOption" value="2">
WPA2-personal [AES]
</label>
<label class="selectOption">
<input type="radio" name="securityOption" value="3">
WPA-Personal [TKIP] + WPA2-Personal [AES]
</label>
<label class="selectOption">
<input type="radio" name="securityOption" value="4">
WPA3-Personal [SAE]
</label>
<label class="selectOption">
<input type="radio" name="securityOption" value="5">
WPA2-personal [AES] + WPA3-Personal
</label>
Security Options
</label>
<label class="inputName">
<input type="password" name="wirelessName" value="SomeRandomPassword"/>
Password (Network)
</label>
</form>
</section>
<div class="seperator"></div>
</div> </div>
</template> </template>

View file

@ -15,7 +15,7 @@ import BasicGuestNetwork from "../pages/basicDashboard/GuestNetwork.vue"
const routes = [ const routes = [
{ {
path: '/', path: '/',
component: BasicDashboard, redirect: '/basic'
}, },
{ {
path: '/advance', path: '/advance',

View file

@ -1,3 +1,10 @@
.error {
text-align: center;
width: 100%;
margin-top: 30px;
font-size: 2rem;
}
#basicDashboard { #basicDashboard {
display: flex; display: flex;
margin-top: 20px; margin-top: 20px;
@ -102,56 +109,79 @@
} }
} }
#internetSetupComponent { #internetSetupComponent, #wirelessSettingsComponent {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 20px; gap: 20px;
align-items: center;
max-width: 70%;
margin: auto;
section { section {
margin-bottom: 10px; margin-bottom: 10px;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 10px; gap: 10px;
width: 400px;
}
input[type="radio"] {
appearance: none;
-webkit-appearance: none;
width: 1.15em;
height:1.15em;
border: 0.15em solid #fff;
border-radius: 10%;
display: flex;
align-items: center;
justify-content: center;
}
input[type="radio"]::before {
content: "";
width: 100%; width: 100%;
height: 100%;
border-radius: 10%;
transform: scale(0);
transition: 0.3s transform;
background-color: var(--dark-highlight-color);
} }
input[type="radio"]:checked::before { form {
transform: scale(1); display: flex;
flex-direction: column;
gap: 10px;
} }
label {
margin-top: 5px; .seperator {
margin-top: 20px;
}
.selectOption {
display: flex; display: flex;
align-items: center; align-items: center;
background-color: var(--dark-bg-alt-2-color); background-color: var(--dark-bg-alt-2-color);
height: 50px; min-height: 50px;
width: 100%; width: 100%;
border-radius: 5px; border-radius: 5px;
padding: 10px; padding: 10px;
font-size: 1.2rem;
p { user-select: none;
margin-left: 10px; cursor: pointer;
}
.inputName {
display: flex;
flex-direction: column-reverse;
input {
margin-top: 5px;
display: flex;
align-items: center;
background-color: var(--dark-bg-alt-2-color);
min-height: 50px;
width: 100%;
border-radius: 5px;
padding: 10px;
font-size: 1.2rem; font-size: 1.2rem;
border: none;
color: #fff;
} }
} }
.dropdownBox {
display: flex;
flex-direction: column-reverse;
select {
margin-top: 5px;
display: flex;
align-items: center;
background-color: var(--dark-bg-alt-2-color);
min-height: 50px;
width: 100%;
border-radius: 5px;
padding: 10px;
font-size: 1.2rem;
border: none;
color: #fff;
}
}
.subSelect {
display: flex;
flex-direction: column-reverse;
gap: 5px;
}
} }

View file

@ -33,6 +33,7 @@ body {
font-family: Noto-Sans, sans-serif; font-family: Noto-Sans, sans-serif;
min-height: 100vh; min-height: 100vh;
padding: var(--padding); padding: var(--padding);
overflow-x: hidden;
} }
a { a {
@ -83,6 +84,40 @@ a {
} }
} }
#footer {
display: flex;
align-items: center;
justify-content: space-between;
background-color: var(--dark-bg-alt-2-color);
width: 70%;
margin: 20px auto;
padding: 15px;
border-radius: 5px;
div {
display: flex;
gap: 10px;
float: right;
}
button {
color: inherit;
background-color: var(--dark-bg-alt-2-color);
border: none;
height: 40px;
width: 70px;
border-radius: 5px;
cursor: pointer;
font-size: 1rem;
text-underline-offset: 2px;
}
button:hover {
text-decoration: underline;
}
.apply {
background-color: var(--dark-highlight-color);
}
}
.popup { .popup {
position: relative; position: relative;
height: min-content; height: min-content;
@ -121,3 +156,40 @@ a {
.bad-indicator { .bad-indicator {
background-color: var(--bad-indicator) !important; background-color: var(--bad-indicator) !important;
} }
.seperator {
background-color: #4c4c4c;
height: 2px;
width: 100%;
}
input[type="radio"], input[type="checkbox"] {
appearance: none;
-webkit-appearance: none;
width: 15px;
height:15px;
border: 2px solid #fff;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
margin-right: 10px;
}
input[type="radio"]::before, input[type="checkbox"]::before {
content: "";
width: 100%;
height: 100%;
border-radius: 50%;
transform: scale(0);
transition: 0.3s transform;
background-color: var(--dark-highlight-color);
}
input[type="radio"]:checked::before, input[type="checkbox"]:checked::before {
transform: scale(1);
}
input[type="checkbox"], input[type="checkbox"]::before {
border-radius: 10%;
}