Add save password option on login page w/ clients card on index
This commit is contained in:
48
src_assets/common/assets/web/ClientCard.vue
Normal file
48
src_assets/common/assets/web/ClientCard.vue
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
<template>
|
||||||
|
<div class="card p-2">
|
||||||
|
<div class="card-body">
|
||||||
|
<h2>{{ $t('client_card.clients') }}</h2>
|
||||||
|
<br>
|
||||||
|
<p>{{ $t('client_card.clients_desc') }}</p>
|
||||||
|
<div class="card-group p-4 align-items-center">
|
||||||
|
<a v-for="{ platform, icon, name, link } of clients" class="btn m-1" :class="[link && 'btn-success' || 'btn-secondary']" :href="link" target="_blank" @click="shouldOpen($event, link)"><i v-if="icon" :class="icon"></i> <span class="platform-text">{{ platform }}</span> [ {{ name }} ] </a>
|
||||||
|
</div>
|
||||||
|
<i>* {{ $t('client_card.generic_moonlight_clients_desc') }}</i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.platform-text {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
const clients = [
|
||||||
|
{
|
||||||
|
platform: 'Android',
|
||||||
|
icon: 'fa-brands fa-android',
|
||||||
|
name: 'Artemis',
|
||||||
|
link: 'https://github.com/ClassicOldSong/moonlight-android'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
platform: 'iOS',
|
||||||
|
icon: 'fa-brands fa-apple',
|
||||||
|
name: 'Coming soon...',
|
||||||
|
link: ''
|
||||||
|
},
|
||||||
|
{
|
||||||
|
platform: 'Desktop',
|
||||||
|
icon: 'fa-solid fa-desktop',
|
||||||
|
name: 'Coming soon...',
|
||||||
|
link: ''
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
const shouldOpen = (e, link) => {
|
||||||
|
if (!link) {
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="card p-2">
|
<div class="card p-2 mt-4">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h2>{{ $t('resource_card.resources') }}</h2>
|
<h2>{{ $t('resource_card.resources') }}</h2>
|
||||||
<br>
|
<br>
|
||||||
|
|||||||
@@ -68,6 +68,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<!-- Resources -->
|
<!-- Resources -->
|
||||||
<div class="my-4">
|
<div class="my-4">
|
||||||
|
<Client-Card></Client-Card>
|
||||||
<Resource-Card></Resource-Card>
|
<Resource-Card></Resource-Card>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -77,6 +78,7 @@
|
|||||||
import { createApp } from 'vue'
|
import { createApp } from 'vue'
|
||||||
import { initApp } from './init'
|
import { initApp } from './init'
|
||||||
import Navbar from './Navbar.vue'
|
import Navbar from './Navbar.vue'
|
||||||
|
import ClientCard from './ClientCard.vue'
|
||||||
import ResourceCard from './ResourceCard.vue'
|
import ResourceCard from './ResourceCard.vue'
|
||||||
import ApolloVersion from './apollo_version'
|
import ApolloVersion from './apollo_version'
|
||||||
|
|
||||||
@@ -84,6 +86,7 @@
|
|||||||
let app = createApp({
|
let app = createApp({
|
||||||
components: {
|
components: {
|
||||||
Navbar,
|
Navbar,
|
||||||
|
ClientCard,
|
||||||
ResourceCard
|
ResourceCard
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
|
|||||||
@@ -21,11 +21,15 @@
|
|||||||
<input type="text" class="form-control" id="usernameInput" autocomplete="username"
|
<input type="text" class="form-control" id="usernameInput" autocomplete="username"
|
||||||
v-model="passwordData.username" required autofocus/>
|
v-model="passwordData.username" required autofocus/>
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-4">
|
<div class="mb-2">
|
||||||
<label for="passwordInput" class="form-label">{{ $t('_common.password') }}</label>
|
<label for="passwordInput" class="form-label">{{ $t('_common.password') }}</label>
|
||||||
<input type="password" class="form-control" id="passwordInput" autocomplete="password"
|
<input type="password" class="form-control" id="passwordInput" autocomplete="password"
|
||||||
v-model="passwordData.password" required />
|
v-model="passwordData.password" required />
|
||||||
</div>
|
</div>
|
||||||
|
<div class="mb-3 form-check">
|
||||||
|
<label for="savePassword" class="form-check-label">{{ $t('login.save_password') }}</label>
|
||||||
|
<input type="checkbox" class="form-check-input" id="savePassword" v-model="savePassword"/>
|
||||||
|
</div>
|
||||||
<button type="submit" class="btn btn-primary w-100 mb-2" v-bind:disabled="loading">
|
<button type="submit" class="btn btn-primary w-100 mb-2" v-bind:disabled="loading">
|
||||||
{{ $t('welcome.login') }}
|
{{ $t('welcome.login') }}
|
||||||
</button>
|
</button>
|
||||||
@@ -44,16 +48,36 @@
|
|||||||
import { initApp } from './init'
|
import { initApp } from './init'
|
||||||
|
|
||||||
let app = createApp({
|
let app = createApp({
|
||||||
data() {
|
setup() {
|
||||||
|
const savedPasswordStr = localStorage.getItem('login')
|
||||||
|
if (savedPasswordStr) {
|
||||||
|
try {
|
||||||
|
const { username, password } = JSON.parse(savedPasswordStr);
|
||||||
|
return {
|
||||||
|
error: null,
|
||||||
|
success: false,
|
||||||
|
loading: false,
|
||||||
|
savePassword: true,
|
||||||
|
passwordData: {
|
||||||
|
username,
|
||||||
|
password
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Reading saved password failed!', e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
error: null,
|
error: null,
|
||||||
success: false,
|
success: false,
|
||||||
loading: false,
|
loading: false,
|
||||||
|
savePassword: false,
|
||||||
passwordData: {
|
passwordData: {
|
||||||
username: "",
|
username: "",
|
||||||
password: ""
|
password: ""
|
||||||
},
|
},
|
||||||
};
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
save() {
|
save() {
|
||||||
@@ -66,6 +90,7 @@
|
|||||||
this.loading = false;
|
this.loading = false;
|
||||||
if (res.status === 200) {
|
if (res.status === 200) {
|
||||||
this.success = true;
|
this.success = true;
|
||||||
|
localStorage.setItem('login', JSON.stringify(this.passwordData));
|
||||||
location.href = './';
|
location.href = './';
|
||||||
} else {
|
} else {
|
||||||
if (res.status === 401) {
|
if (res.status === 401) {
|
||||||
|
|||||||
@@ -87,6 +87,11 @@
|
|||||||
"resolution_scale_factor": "Resolution Scale Factor",
|
"resolution_scale_factor": "Resolution Scale Factor",
|
||||||
"resolution_scale_factor_desc": "Scale the client requested resolution based on this factor. e.g. 2000x1000 with a factor of 120% will become 2400x1200. Overrides client requested factor when the number isn't 100%. This option won't affect client requested streaming resolution."
|
"resolution_scale_factor_desc": "Scale the client requested resolution based on this factor. e.g. 2000x1000 with a factor of 120% will become 2400x1200. Overrides client requested factor when the number isn't 100%. This option won't affect client requested streaming resolution."
|
||||||
},
|
},
|
||||||
|
"client_card": {
|
||||||
|
"clients": "Clients",
|
||||||
|
"clients_desc": "Clients that are specifically tuned to work the best with Apollo",
|
||||||
|
"generic_moonlight_clients_desc": "Gereric Moonlight clients are still usable with Apollo."
|
||||||
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"adapter_name": "Adapter Name",
|
"adapter_name": "Adapter Name",
|
||||||
"adapter_name_desc_linux_1": "Manually specify a GPU to use for capture.",
|
"adapter_name_desc_linux_1": "Manually specify a GPU to use for capture.",
|
||||||
@@ -341,6 +346,9 @@
|
|||||||
"wan_encryption_mode_2": "Required for all clients",
|
"wan_encryption_mode_2": "Required for all clients",
|
||||||
"wan_encryption_mode_desc": "This determines when encryption will be used when streaming over the Internet. Encryption can reduce streaming performance, particularly on less powerful hosts and clients."
|
"wan_encryption_mode_desc": "This determines when encryption will be used when streaming over the Internet. Encryption can reduce streaming performance, particularly on less powerful hosts and clients."
|
||||||
},
|
},
|
||||||
|
"login": {
|
||||||
|
"save_password": "Remember Password"
|
||||||
|
},
|
||||||
"index": {
|
"index": {
|
||||||
"description": "Apollo is a self-hosted game stream host for Moonlight.",
|
"description": "Apollo is a self-hosted game stream host for Moonlight.",
|
||||||
"download": "Download",
|
"download": "Download",
|
||||||
|
|||||||
@@ -85,6 +85,11 @@
|
|||||||
"resolution_scale_factor": "分辨率缩放比例",
|
"resolution_scale_factor": "分辨率缩放比例",
|
||||||
"resolution_scale_factor_desc": "基于此比例缩放客户端请求的分辨率。例如 2000x1000 缩放 120% 将变成 2400x1200。当此项为非 100% 时覆盖客户端请求的缩放比例。此选项不会影响客户端请求的串流分辨率。"
|
"resolution_scale_factor_desc": "基于此比例缩放客户端请求的分辨率。例如 2000x1000 缩放 120% 将变成 2400x1200。当此项为非 100% 时覆盖客户端请求的缩放比例。此选项不会影响客户端请求的串流分辨率。"
|
||||||
},
|
},
|
||||||
|
"client_card": {
|
||||||
|
"clients": "客户端",
|
||||||
|
"clients_desc": "为 Apollo 精心特调的客户端",
|
||||||
|
"generic_moonlight_clients_desc": "普通 Moonlight 客户端也可与 Apollo 共同使用。"
|
||||||
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"adapter_name": "适配器名称",
|
"adapter_name": "适配器名称",
|
||||||
"adapter_name_desc_linux_1": "手动指定用于捕获的 GPU。",
|
"adapter_name_desc_linux_1": "手动指定用于捕获的 GPU。",
|
||||||
@@ -341,6 +346,9 @@
|
|||||||
"wan_encryption_mode_2": "强制所有客户端使用",
|
"wan_encryption_mode_2": "强制所有客户端使用",
|
||||||
"wan_encryption_mode_desc": "这决定了在公网串流时是否加密。加密会降低串流性能,尤其是在性能较弱的主机和客户端上。"
|
"wan_encryption_mode_desc": "这决定了在公网串流时是否加密。加密会降低串流性能,尤其是在性能较弱的主机和客户端上。"
|
||||||
},
|
},
|
||||||
|
"login": {
|
||||||
|
"save_password": "记住密码"
|
||||||
|
},
|
||||||
"index": {
|
"index": {
|
||||||
"description": "Apollo 是供 Moonlight 使用的自建游戏串流服务。",
|
"description": "Apollo 是供 Moonlight 使用的自建游戏串流服务。",
|
||||||
"download": "下载",
|
"download": "下载",
|
||||||
|
|||||||
Reference in New Issue
Block a user