+
订阅里没有线路
+
@@ -196,54 +276,83 @@ h4 {
font-size: var(--t-xs);
font-weight: 500;
color: var(--c-text-faint);
- margin: var(--s-4) 0 var(--s-2);
+ margin: var(--s-5) 0 var(--s-2);
}
-.chips {
- display: flex;
- flex-wrap: wrap;
+.grid {
+ display: grid;
+ grid-template-columns: repeat(auto-fill, minmax(168px, 1fr));
gap: var(--s-2);
}
-.chip {
- padding: var(--s-1) var(--s-3);
- border: 1px solid var(--c-border-strong);
+.card {
+ display: flex;
+ flex-direction: column;
+ gap: var(--s-1);
+ min-width: 0;
+ padding: var(--s-3);
+ border: 1px solid var(--c-border);
border-radius: var(--r-sm);
- background: var(--c-surface);
- font-family: var(--f-mono);
- font-size: var(--t-sm);
+ background: var(--c-surface-sunken);
+ text-align: left;
cursor: pointer;
- max-width: 100%;
+}
+
+.card:hover:not(:disabled) {
+ border-color: var(--c-accent);
+}
+
+.card.is-on {
+ border-color: var(--c-accent);
+ background: var(--c-accent-soft);
+}
+
+.card:disabled {
+ cursor: not-allowed;
+ opacity: 0.55;
+}
+
+.card-name {
+ font-size: var(--t-sm);
+ font-weight: 500;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
-.chip:hover:not(:disabled) {
- border-color: var(--c-accent);
+.card.is-on .card-name {
color: var(--c-accent-text);
}
-.chip.is-on {
- background: var(--c-accent-soft);
- border-color: var(--c-accent);
- color: var(--c-accent-text);
- font-weight: 500;
-}
-
-.chip:disabled {
- cursor: not-allowed;
+.card-sub {
+ font-size: var(--t-xs);
color: var(--c-text-faint);
- border-color: var(--c-border);
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
}
-.chip.is-on:disabled {
- color: var(--c-accent-text);
- border-color: color-mix(in srgb, var(--c-accent) 45%, transparent);
+.card-delay {
+ font-family: var(--f-mono);
+ font-size: var(--t-xs);
+ font-variant-numeric: tabular-nums;
+ min-height: 1.2em;
}
-.locked,
-.unavailable {
+.d-ok {
+ color: var(--c-ok);
+}
+.d-warn {
+ color: var(--c-warn);
+}
+.d-bad {
+ color: var(--c-danger);
+}
+.d-none {
+ color: transparent;
+}
+
+.aside-note {
display: flex;
align-items: center;
gap: var(--s-2);
@@ -253,7 +362,7 @@ h4 {
line-height: 1.6;
}
-.locked code {
+.aside-note code {
color: var(--c-text-soft);
}
diff --git a/web/views/RouterPage.vue b/web/views/RouterPage.vue
index 98dcc6c..f9fe30a 100644
--- a/web/views/RouterPage.vue
+++ b/web/views/RouterPage.vue
@@ -4,6 +4,7 @@ import { collectInbounds, collectOutboundNames, outboundToProxyField } from '@sh
import type { Inbound, OutboundMode } from '@shared/inbounds.ts'
import type { ConfigObject } from '../../vendor/config-editor/index.ts'
import { ApiError, api } from '../api'
+import type { ProxyInfo } from '../api'
import { density } from '../prefs'
import InboundDetail from './InboundDetail.vue'
import IconAdd from '~icons/ri/add-line'
@@ -13,6 +14,7 @@ const props = defineProps<{
revision: string
kernelOnline: boolean
providerLines: string[]
+ runtime: Record
}>()
const emit = defineEmits<{ changed: [] }>()
@@ -145,6 +147,7 @@ async function pickOutbound(mode: OutboundMode) {
:groups="outbounds.groups"
:own-proxies="outbounds.ownProxies"
:provider-lines="providerLines"
+ :runtime="runtime"
:kernel-online="kernelOnline"
:saving="saving"
@pick="pickOutbound"
@@ -251,7 +254,6 @@ async function pickOutbound(mode: OutboundMode) {
gap: var(--s-3);
padding: var(--s-3) var(--s-4);
border: none;
- border-left: 2px solid transparent;
background: none;
cursor: pointer;
text-align: left;
@@ -263,7 +265,6 @@ async function pickOutbound(mode: OutboundMode) {
.line.is-on {
background: var(--c-accent-soft);
- border-left-color: var(--c-accent);
}
.port {