Interface for services
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>yunyuyuan 导航</title>
<meta name="viewport" content="width=device-width,initial-scale=1">
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/3.2.47/vue.global.prod.min.js"></script>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
}
html, body {
width: 100%;
height: 100%;
overflow: hidden;
}
body {
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
display: flex;
align-items: center;
justify-content: center;
}
#wrapper {
display: block;
height: 100%;
width: 100%;
overflow-y: auto;
}
#content {
max-width: 1200px;
margin: 0 auto;
padding: 20px;
}
.header {
text-align: center;
margin-bottom: 30px;
}
.header h1 {
font-size: 2.5rem;
color: #2d3748;
margin-bottom: 10px;
}
.switch-container {
display: flex;
justify-content: center;
background: rgba(255, 255, 255, 0.8);
border-radius: 12px;
padding: 10px;
margin: 0 auto 20px auto;
max-width: 600px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);
}
.switch-container span {
cursor: pointer;
font-size: 16px;
padding: 8px 16px;
border-radius: 8px;
transition: all 0.2s ease;
margin: 0 4px;
color: #4a5568;
}
.switch-container span:hover {
background: rgba(0, 0, 0, 0.05);
}
.switch-container span.active {
background: #3182ce;
color: white;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.units {
background: rgba(255, 255, 255, 0.8);
border-radius: 12px;
margin: 0 0 20px 0;
padding: 15px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);
}
.units > p {
font-size: 20px;
font-weight: 600;
color: #2d3748;
padding: 10px 0;
margin-bottom: 10px;
border-bottom: 1px solid #e2e8f0;
}
.links-container {
display: flex;
flex-wrap: wrap;
gap: 10px;
}
.units a {
font-size: 16px;
color: #4a5568;
padding: 10px 15px;
border-radius: 8px;
text-decoration: none;
background: white;
transition: all 0.2s ease;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}
.units a:not(.disabled):hover {
background: #3182ce;
color: white;
transform: translateY(-2px);
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}
.units a.disabled {
cursor: not-allowed;
background: #edf2f7;
color: #a0aec0;
}
@media (max-width: 768px) {
.switch-container {
overflow-x: auto;
justify-content: flex-start;
padding: 10px 5px;
}
.units a {
padding: 8px 12px;
font-size: 14px;
}
}
</style>
</head>
<body>
<div id="wrapper">
<div id="content">
<div class="switch-container">
<span @click="currentType='direct'" :class="{active: currentType==='direct'}">直连</span>
<span @click="currentType='cf'" :class="{active: currentType==='cf'}">CF Tunnel</span>
<span @click="currentType='ts'" :class="{active: currentType==='ts'}">Tailscale</span>
<span @click="currentType='vpn'" :class="{active: currentType==='vpn'}">VPN</span>
<span @click="currentType='cdn'" :class="{active: currentType==='cdn'}">CF CDN</span>
</div>
<div class="units" v-for="machine of machines">
<p>{{ machine.name }}</p>
<div class="links-container">
<a v-for="domain of machine.domains" :href="domain.domain.value || null"
:class="{disabled: !domain.domain.value}"
@click="clickEvent($event, domain)">{{ domain.name }}</a>
</div>
</div>
</div>
</div>
</body>
<script>
Vue.createApp({
setup() {
const currentType = Vue.ref('direct');
fetch('https://i-d.yunyuyuan.net:8888').then((res) => {
if (res.status !== 200) {
currentType.value = 'cf';
}
}).catch(() => {
currentType.value = 'cf';
})
function getDomainRef(direct, cf='', ts='', vpn='', cdn='') {
return Vue.computed(() => {
switch (currentType.value) {
case 'direct':
return direct;
case 'cf':
return cf;
case 'ts':
return ts;
case 'vpn':
return vpn;
case 'cdn':
return cdn;
}
})
}
function commonRef(s, withPort = true, suffix = '') {
return getDomainRef(`https://${s}-d.yunyuyuan.net${withPort ? ':8888': ''}${suffix}`,
`https://${s}-cf.yunyuyuan.net${suffix}`,
`https://${s}-ts.yunyuyuan.net${suffix}`,
`https://${s}-v.yunyuyuan.net${suffix}`, withPort ? '' : `https://${s}-cdn.yunyuyuan.net${suffix}`);
}
function sameRef(s) {
return getDomainRef(s, s, s, s, s);
}
function clickEvent(e, domain) {
if(!domain.domain.value || domain.click){
e.preventDefault();
if (domain.click) {
domain.click(domain.domain.value);
}
}
}
return {
currentType,
clickEvent,
machines: [
{
name: 'Arch',
domains: [
{
name: '云盘',
domain: commonRef('file'),
},
{
name: '视频',
domain: commonRef('video'),
},
{
name: 'bitTorrent',
domain: commonRef('download'),
},
{
name: 'money',
domain: commonRef('money'),
},
{
name: '状态',
domain: commonRef('status'),
},
{
name: '测速',
domain: commonRef('speed'),
},
{
name: '照片',
domain: commonRef('photo'),
},
{
name: 'filebrowser',
domain: commonRef('fb'),
},
{
name: 'gitea',
domain: commonRef('git'),
},
{
name: 'code-server',
domain: commonRef('code-server'),
},
{
name: 'ttyd',
domain: commonRef('ttyd'),
},
{
name: 'novnc',
domain: commonRef('novnc'),
},
{
name: 'hass',
domain: commonRef('hass'),
},
{
name: 'aria2',
domain: commonRef('aria'),
},
{
name: 'rss',
domain: commonRef('rss'),
},
{
name: 'docker',
domain: commonRef('docker'),
},
{
name: 'note',
domain: commonRef('note'),
},
{
name: 'blog',
domain: commonRef('blog-drone'),
},
{
name: 'drone',
domain: commonRef('drone'),
},
{
name: 'gotify',
domain: commonRef('gotify'),
},
{
name: 'music',
domain: commonRef('music'),
},
{
name: 'st',
domain: commonRef('st'),
},
{
name: 'SSH-CF',
domain: sameRef(`https://ssh-cf.yunyuyuan.net`),
},
],
},
{
name: 'Scaleway ipv6',
domains: [
{
name: 'ttyd',
domain: commonRef('ttyd-sw', false),
},
{
name: '测速',
domain: commonRef('speed-sw', false),
},
{
name: 'oss filebrowser',
domain: commonRef('fb-sw', false),
},
{
name: 'SSH-CF',
domain: sameRef(`https://ssh-sw-cf.yunyuyuan.net`),
},
],
},
{
name: 'Raspberry Pi',
domains: [
{
name: 'openwrt',
domain: commonRef('pi-router'),
},
{
name: 'clash',
domain: commonRef('clash-pi-router', true, '/ui/yacd'),
},
{
name: 'ttyd',
domain: commonRef('ttyd-pi-router'),
},
{
name: 'SSH-CF',
domain: sameRef(`https://ssh-pi-router-cf.yunyuyuan.net`),
},
],
},
{
name: 'Router',
domains: [
{
name: 'openwrt',
domain: commonRef('router'),
},
{
name: 'clash',
domain: commonRef('clash-router', true, '/ui/yacd'),
},
{
name: 'ttyd',
domain: getDomainRef('ttyd-router'),
},
],
},
{
name: 'Other',
domains: [
{
name: 'openwebui',
domain: sameRef('http://localhost:16020'),
},
],
},
]
}
}
}).mount('#content')
</script>
</html>