account: polish Wolf card
This commit is contained in:
parent
9ff34e7661
commit
8126bd3c96
@ -1,7 +1,10 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="card module wolf-card" :style="{ order: 0 }">
|
<div class="card module wolf-card" :style="{ order: 0 }">
|
||||||
<div class="module-head">
|
<div class="module-head">
|
||||||
|
<div>
|
||||||
<h2>Wolf</h2>
|
<h2>Wolf</h2>
|
||||||
|
<p class="muted wolf-subtitle">Game streaming access for Moonlight.</p>
|
||||||
|
</div>
|
||||||
<span
|
<span
|
||||||
class="pill mono"
|
class="pill mono"
|
||||||
:class="
|
:class="
|
||||||
@ -17,36 +20,54 @@
|
|||||||
{{ wolf.loading ? "loading..." : wolf.status }}
|
{{ wolf.loading ? "loading..." : wolf.status }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="kv">
|
<div class="wolf-connection">
|
||||||
<div class="row">
|
<div>
|
||||||
<span class="k mono">Moonlight host</span>
|
<span class="k mono">Moonlight host</span>
|
||||||
<span class="v mono">{{ wolf.moonlightHost }}</span>
|
<div class="wolf-host mono">{{ wolf.moonlightHost }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
<button class="copy mono" type="button" @click="copyHost">
|
||||||
|
{{ copiedHost ? "copied" : "copy" }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="wolf-summary">
|
||||||
|
<div class="wolf-summary-item">
|
||||||
|
<span class="k mono">GPU</span>
|
||||||
|
<strong class="mono">{{ wolf.gpuPriority }}</strong>
|
||||||
|
</div>
|
||||||
|
<div class="wolf-summary-item">
|
||||||
|
<span class="k mono">Firewall</span>
|
||||||
|
<strong class="mono" :class="currentIpUnlocked ? 'ok-text' : 'warn-text'">
|
||||||
|
{{ currentIpUnlocked ? "open" : "locked" }}
|
||||||
|
</strong>
|
||||||
|
</div>
|
||||||
|
<div class="wolf-summary-item">
|
||||||
|
<span class="k mono">Sessions</span>
|
||||||
|
<strong class="mono">{{ wolf.sessions.length }}</strong>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="kv wolf-detail">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<span class="k mono">Your IP</span>
|
<span class="k mono">Current IP</span>
|
||||||
<span class="v mono">{{ wolf.sourceIp || "unknown" }}</span>
|
<span class="v mono">{{ wolf.sourceIp || "unknown" }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<span class="k mono">GPU priority</span>
|
<span class="k mono">Active unlocks</span>
|
||||||
<span class="v mono">{{ wolf.gpuPriority }}</span>
|
|
||||||
</div>
|
|
||||||
<div class="row">
|
|
||||||
<span class="k mono">Firewall unlocks</span>
|
|
||||||
<span class="v mono">{{ wolf.activeUnlocks.length }}</span>
|
<span class="v mono">{{ wolf.activeUnlocks.length }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<span class="k mono">Paired devices</span>
|
<span class="k mono">Paired devices</span>
|
||||||
<span class="v mono">{{ wolf.clients.map((client) => client.name).join(", ") || "none" }}</span>
|
<span class="v mono">{{ pairedDeviceNames }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="actions">
|
<div class="actions">
|
||||||
<button class="primary" type="button" :disabled="wolf.unlocking" @click="$emit('unlock')">
|
<button class="primary" type="button" :disabled="wolf.unlocking" @click="$emit('unlock')">
|
||||||
{{ wolf.unlocking ? "Unlocking..." : "Unlock Moonlight" }}
|
{{ wolf.unlocking ? "Unlocking..." : currentIpUnlocked ? "Refresh unlock" : "Unlock Moonlight" }}
|
||||||
</button>
|
</button>
|
||||||
<button class="copy mono" type="button" :disabled="wolf.loading" @click="$emit('refresh')">Refresh</button>
|
<button class="copy mono" type="button" :disabled="wolf.loading" @click="$emit('refresh')">Refresh</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="hint mono">Use the host above in Moonlight after unlocking your current IP.</div>
|
|
||||||
|
|
||||||
<div v-if="wolf.pendingPairRequests.length" class="secret-box">
|
<div v-if="wolf.pendingPairRequests.length" class="secret-box">
|
||||||
<div class="secret-head">
|
<div class="secret-head">
|
||||||
@ -72,6 +93,7 @@
|
|||||||
<div v-if="wolf.canControlGpu" class="secret-box">
|
<div v-if="wolf.canControlGpu" class="secret-box">
|
||||||
<div class="secret-head">
|
<div class="secret-head">
|
||||||
<div class="pill mono">Admin</div>
|
<div class="pill mono">Admin</div>
|
||||||
|
<span class="hint mono">GPU priority</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="wolf-controls">
|
<div class="wolf-controls">
|
||||||
<select v-model="wolf.selectedGame" class="input mono">
|
<select v-model="wolf.selectedGame" class="input mono">
|
||||||
@ -105,7 +127,9 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
defineProps({
|
import { computed, ref } from "vue";
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
wolf: {
|
wolf: {
|
||||||
type: Object,
|
type: Object,
|
||||||
required: true,
|
required: true,
|
||||||
@ -113,6 +137,31 @@ defineProps({
|
|||||||
});
|
});
|
||||||
|
|
||||||
defineEmits(["refresh", "unlock", "pair", "game-mode", "admin-unlock"]);
|
defineEmits(["refresh", "unlock", "pair", "game-mode", "admin-unlock"]);
|
||||||
|
|
||||||
|
const copiedHost = ref(false);
|
||||||
|
|
||||||
|
const currentIpUnlocked = computed(() => {
|
||||||
|
const sourceIp = props.wolf.sourceIp;
|
||||||
|
if (!sourceIp) return false;
|
||||||
|
return props.wolf.activeUnlocks.some((unlock) => unlock?.ip === sourceIp);
|
||||||
|
});
|
||||||
|
|
||||||
|
const pairedDeviceNames = computed(() => {
|
||||||
|
const names = props.wolf.clients.map((client) => client.name).filter(Boolean);
|
||||||
|
return names.length ? names.join(", ") : "none";
|
||||||
|
});
|
||||||
|
|
||||||
|
async function copyHost() {
|
||||||
|
try {
|
||||||
|
await navigator.clipboard?.writeText(props.wolf.moonlightHost || "moonlight.bstein.dev");
|
||||||
|
} catch {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
copiedHost.value = true;
|
||||||
|
window.setTimeout(() => {
|
||||||
|
copiedHost.value = false;
|
||||||
|
}, 1600);
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped src="../styles/account.css"></style>
|
<style scoped src="../styles/account.css"></style>
|
||||||
|
|||||||
@ -88,6 +88,66 @@ h1 {
|
|||||||
margin: 10px 0 0;
|
margin: 10px 0 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.wolf-subtitle {
|
||||||
|
margin-top: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wolf-connection {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 12px;
|
||||||
|
margin-top: 14px;
|
||||||
|
padding: 12px;
|
||||||
|
border: 1px solid rgba(125, 208, 255, 0.22);
|
||||||
|
border-radius: 12px;
|
||||||
|
background: rgba(125, 208, 255, 0.06);
|
||||||
|
}
|
||||||
|
|
||||||
|
.wolf-host {
|
||||||
|
margin-top: 4px;
|
||||||
|
color: var(--accent-cyan);
|
||||||
|
overflow-wrap: anywhere;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wolf-summary {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||||
|
gap: 8px;
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wolf-summary-item {
|
||||||
|
min-width: 0;
|
||||||
|
padding: 10px;
|
||||||
|
border: 1px solid var(--card-border);
|
||||||
|
border-radius: 12px;
|
||||||
|
background: rgba(255, 255, 255, 0.025);
|
||||||
|
}
|
||||||
|
|
||||||
|
.wolf-summary-item span,
|
||||||
|
.wolf-summary-item strong {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wolf-summary-item strong {
|
||||||
|
margin-top: 4px;
|
||||||
|
color: var(--text-strong);
|
||||||
|
overflow-wrap: anywhere;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wolf-detail {
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ok-text {
|
||||||
|
color: rgba(120, 255, 160, 0.95) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.warn-text {
|
||||||
|
color: rgba(255, 207, 104, 0.95) !important;
|
||||||
|
}
|
||||||
|
|
||||||
.kv {
|
.kv {
|
||||||
margin-top: 12px;
|
margin-top: 12px;
|
||||||
border: 1px solid var(--card-border);
|
border: 1px solid var(--card-border);
|
||||||
@ -273,6 +333,15 @@ button.primary {
|
|||||||
align-items: stretch;
|
align-items: stretch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.wolf-connection {
|
||||||
|
align-items: stretch;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wolf-summary {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
.pair-row,
|
.pair-row,
|
||||||
.wolf-controls,
|
.wolf-controls,
|
||||||
.manual-unlock {
|
.manual-unlock {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user