@swimmingliu/autovpn 1.6.1 → 1.6.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1280,7 +1280,7 @@ body[data-page="logs"] #logCenterTable {
1280
1280
 
1281
1281
  .source-drawer-settings {
1282
1282
  display: grid;
1283
- grid-template-columns: repeat(3, minmax(160px, 1fr));
1283
+ grid-template-columns: repeat(4, minmax(0, 1fr));
1284
1284
  gap: 12px;
1285
1285
  }
1286
1286
 
@@ -2015,4 +2015,324 @@ body[data-page="logs"] #logCenterTable {
2015
2015
  flex-direction: column;
2016
2016
  align-items: flex-start;
2017
2017
  }
2018
+
2019
+ .source-drawer-settings {
2020
+ grid-template-columns: repeat(2, minmax(0, 1fr));
2021
+ }
2022
+ }
2023
+
2024
+ @media (max-width: 720px) {
2025
+ html,
2026
+ body,
2027
+ .app-frame,
2028
+ .app-content-shell {
2029
+ min-height: 100%;
2030
+ }
2031
+
2032
+ body {
2033
+ overflow: auto;
2034
+ background: linear-gradient(180deg, #fbfcff 0%, var(--bg) 100%);
2035
+ }
2036
+
2037
+ .app-frame {
2038
+ display: block;
2039
+ height: auto;
2040
+ }
2041
+
2042
+ .workspace-shell {
2043
+ display: block;
2044
+ min-height: 100vh;
2045
+ padding-bottom: calc(76px + env(safe-area-inset-bottom));
2046
+ }
2047
+
2048
+ .sidebar {
2049
+ position: fixed;
2050
+ left: 0;
2051
+ right: 0;
2052
+ bottom: 0;
2053
+ z-index: 80;
2054
+ display: block;
2055
+ padding: 8px 10px calc(8px + env(safe-area-inset-bottom));
2056
+ border: 1px solid rgba(207, 215, 239, 0.82);
2057
+ border-width: 1px 0 0;
2058
+ background: rgba(255, 255, 255, 0.96);
2059
+ box-shadow: 0 -16px 34px rgba(29, 39, 71, 0.12);
2060
+ backdrop-filter: blur(18px);
2061
+ }
2062
+
2063
+ .sidebar-brand {
2064
+ display: none;
2065
+ }
2066
+
2067
+ .sidebar-nav {
2068
+ display: grid;
2069
+ grid-template-columns: repeat(6, minmax(0, 1fr));
2070
+ gap: 4px;
2071
+ overflow: visible;
2072
+ padding: 0;
2073
+ }
2074
+
2075
+ .nav-item {
2076
+ min-height: 58px;
2077
+ display: grid;
2078
+ justify-items: center;
2079
+ align-content: center;
2080
+ gap: 4px;
2081
+ padding: 4px 2px;
2082
+ border-radius: 14px;
2083
+ }
2084
+
2085
+ .nav-icon {
2086
+ min-width: 0;
2087
+ width: 28px;
2088
+ height: 28px;
2089
+ border-radius: 10px;
2090
+ font-size: 13px;
2091
+ letter-spacing: 0;
2092
+ }
2093
+
2094
+ .nav-copy {
2095
+ display: block;
2096
+ max-width: 100%;
2097
+ font-size: 11px;
2098
+ line-height: 1.1;
2099
+ font-weight: 800;
2100
+ white-space: nowrap;
2101
+ }
2102
+
2103
+ .main-shell {
2104
+ display: block;
2105
+ min-height: auto;
2106
+ padding: 12px 12px 18px;
2107
+ }
2108
+
2109
+ .topbar {
2110
+ position: sticky;
2111
+ top: 0;
2112
+ z-index: 40;
2113
+ grid-template-columns: 1fr;
2114
+ gap: 12px;
2115
+ padding: 14px;
2116
+ border-radius: 20px;
2117
+ backdrop-filter: blur(18px);
2118
+ }
2119
+
2120
+ .topbar-heading h1 {
2121
+ font-size: 26px;
2122
+ line-height: 1.1;
2123
+ letter-spacing: 0;
2124
+ }
2125
+
2126
+ .topbar-heading p {
2127
+ display: none;
2128
+ }
2129
+
2130
+ .page-title-row {
2131
+ justify-content: space-between;
2132
+ }
2133
+
2134
+ .topbar-actions {
2135
+ display: grid;
2136
+ grid-template-columns: repeat(3, minmax(0, 1fr));
2137
+ align-items: stretch;
2138
+ gap: 8px;
2139
+ }
2140
+
2141
+ .topbar-actions .btn {
2142
+ min-width: 0;
2143
+ padding: 0 8px;
2144
+ min-height: 42px;
2145
+ border-radius: 12px;
2146
+ font-size: 13px;
2147
+ }
2148
+
2149
+ .page-content {
2150
+ overflow: visible;
2151
+ padding: 12px 0 0;
2152
+ }
2153
+
2154
+ body[data-page="logs"] .page-content {
2155
+ overflow: visible;
2156
+ }
2157
+
2158
+ .page-shell,
2159
+ .page-grid,
2160
+ .dashboard-grid,
2161
+ .runs-grid,
2162
+ .logs-grid,
2163
+ .results-grid,
2164
+ .subscriptions-grid,
2165
+ .settings-layout,
2166
+ .metric-grid,
2167
+ .metric-grid.four,
2168
+ .country-grid,
2169
+ .action-grid,
2170
+ .action-grid.four {
2171
+ grid-template-columns: 1fr;
2172
+ gap: 12px;
2173
+ }
2174
+
2175
+ .panel,
2176
+ .page-header-card,
2177
+ .topbar {
2178
+ box-shadow: 0 12px 28px rgba(29, 39, 71, 0.08);
2179
+ }
2180
+
2181
+ .panel {
2182
+ border-radius: 18px;
2183
+ padding: 14px;
2184
+ }
2185
+
2186
+ .page-header-card {
2187
+ display: none;
2188
+ }
2189
+
2190
+ .panel-headline {
2191
+ margin-bottom: 12px;
2192
+ }
2193
+
2194
+ .panel-headline h3,
2195
+ .page-header-copy h2 {
2196
+ font-size: 20px;
2197
+ letter-spacing: 0;
2198
+ }
2199
+
2200
+ .status-hero-card,
2201
+ .artifact-card,
2202
+ .subscription-meta,
2203
+ .about-card {
2204
+ align-items: flex-start;
2205
+ }
2206
+
2207
+ .status-hero-card h3 {
2208
+ font-size: 26px;
2209
+ }
2210
+
2211
+ .status-orb {
2212
+ width: 54px;
2213
+ height: 54px;
2214
+ font-size: 24px;
2215
+ }
2216
+
2217
+ .flow-steps {
2218
+ grid-template-columns: 1fr;
2219
+ }
2220
+
2221
+ .flow-step {
2222
+ display: grid;
2223
+ grid-template-columns: 44px minmax(0, 1fr);
2224
+ align-items: center;
2225
+ text-align: left;
2226
+ gap: 10px;
2227
+ padding: 12px;
2228
+ }
2229
+
2230
+ .flow-icon {
2231
+ width: 42px;
2232
+ height: 42px;
2233
+ margin: 0;
2234
+ }
2235
+
2236
+ .run-control-panel {
2237
+ position: sticky;
2238
+ bottom: calc(76px + env(safe-area-inset-bottom));
2239
+ z-index: 35;
2240
+ grid-template-columns: repeat(2, minmax(0, 1fr));
2241
+ gap: 10px;
2242
+ background: rgba(255, 255, 255, 0.98);
2243
+ backdrop-filter: blur(16px);
2244
+ }
2245
+
2246
+ .run-big {
2247
+ min-height: 50px;
2248
+ border-radius: 14px;
2249
+ }
2250
+
2251
+ .retry-control-card {
2252
+ grid-template-columns: 1fr;
2253
+ gap: 10px;
2254
+ padding: 12px;
2255
+ border-radius: 14px;
2256
+ }
2257
+
2258
+ .toolbar-row,
2259
+ .toolbar-row.log-toolbar,
2260
+ .toolbar-left,
2261
+ .toolbar-right {
2262
+ display: grid;
2263
+ grid-template-columns: 1fr;
2264
+ align-items: stretch;
2265
+ gap: 8px;
2266
+ }
2267
+
2268
+ .toolbar-left {
2269
+ grid-template-columns: repeat(2, minmax(0, 1fr));
2270
+ }
2271
+
2272
+ .toolbar-right .btn,
2273
+ .subtab {
2274
+ width: 100%;
2275
+ }
2276
+
2277
+ .terminal-output,
2278
+ .log-stream {
2279
+ max-height: 58vh;
2280
+ min-height: 320px;
2281
+ overflow: auto;
2282
+ border-radius: 14px;
2283
+ }
2284
+
2285
+ body[data-page="logs"] #logsWorkspace,
2286
+ body[data-page="logs"] #logsWorkspace > .panel {
2287
+ min-height: auto;
2288
+ height: auto;
2289
+ }
2290
+
2291
+ body[data-page="logs"] #logCenterTable {
2292
+ height: 58vh;
2293
+ }
2294
+
2295
+ .table-like,
2296
+ .node-table,
2297
+ .output-list {
2298
+ overflow-x: auto;
2299
+ }
2300
+
2301
+ .settings-drawer-panel {
2302
+ width: 100vw;
2303
+ max-width: none;
2304
+ height: 100vh;
2305
+ max-height: none;
2306
+ border-radius: 0;
2307
+ transform: none !important;
2308
+ }
2309
+
2310
+ .settings-drawer-body {
2311
+ max-height: calc(100vh - 154px);
2312
+ overflow: auto;
2313
+ }
2314
+
2315
+ .source-drawer-settings {
2316
+ grid-template-columns: 1fr;
2317
+ }
2318
+
2319
+ .toast-root {
2320
+ left: 12px;
2321
+ right: 12px;
2322
+ bottom: calc(86px + env(safe-area-inset-bottom));
2323
+ }
2324
+ }
2325
+
2326
+ @media (max-width: 380px) {
2327
+ .nav-copy {
2328
+ font-size: 10px;
2329
+ }
2330
+
2331
+ .topbar-actions {
2332
+ grid-template-columns: 1fr;
2333
+ }
2334
+
2335
+ .toolbar-left {
2336
+ grid-template-columns: 1fr;
2337
+ }
2018
2338
  }
@@ -175,7 +175,8 @@ export function buildViewModel(state, messages, language) {
175
175
  runStateLabel: messages.runStateLabels[state.runState] ?? messages.runStateLabels.idle,
176
176
  runStateTone: runStateTone(state.runState),
177
177
  settingsDrawer: state.settingsDrawer ?? null,
178
- modalTransform: state.modalTransform ?? ''
178
+ modalTransform: state.modalTransform ?? '',
179
+ runtime: state.runtime ?? 'electron'
179
180
  };
180
181
  }
181
182
 
@@ -587,7 +588,7 @@ function buildLogsPage(vm, messages) {
587
588
  <div class="toolbar-right">
588
589
  <button class="btn btn-secondary small" data-action="copy-log" type="button">复制日志</button>
589
590
  <button class="btn btn-secondary small" data-action="clear-log" type="button">清空显示</button>
590
- <button class="btn btn-primary small" data-action="open-log-file" type="button">打开日志文件</button>
591
+ ${vm.runtime === 'web' ? '' : '<button class="btn btn-primary small" data-action="open-log-file" type="button">打开日志文件</button>'}
591
592
  </div>
592
593
  </div>
593
594
  <div id="logCenterTable" class="terminal-output log-stream">
@@ -709,6 +710,7 @@ function buildSettingsDrawerBody(section, draft) {
709
710
  return `
710
711
  <div class="source-drawer-settings">
711
712
  ${renderDrawerField('最大迭代次数', 'number', draft?.maxIterations ?? 40, 'sources.maxIterations', true, 'data-source-max-iterations min="1"')}
713
+ ${renderDrawerField('早停次数', 'number', draft?.plateauLimit ?? 20, 'sources.plateauLimit', true, 'data-source-plateau-limit min="1"')}
712
714
  ${renderDrawerField('区域起始', 'number', draft?.areaMin ?? 0, 'sources.areaMin', true, 'data-source-area-min')}
713
715
  ${renderDrawerField('区域结束', 'number', draft?.areaMax ?? 100, 'sources.areaMax', true, 'data-source-area-max')}
714
716
  </div>
@@ -795,6 +797,7 @@ function buildSettingsDrawerBody(section, draft) {
795
797
  ${renderDrawerField('Pages 地址', 'text', draft.pages_project_url, 'deploy.pages_project_url')}
796
798
  ${renderDrawerField('订阅地址', 'text', draft.subscription_url, 'deploy.subscription_url')}
797
799
  ${renderDrawerField('verify 订阅地址', 'text', draft.verify_subscription_url, 'deploy.verify_subscription_url')}
800
+ ${renderDrawerField('最少节点数', 'number', draft.min_final_links ?? 10, 'deploy.min_final_links', false, 'min="0" step="1"')}
798
801
  ${renderDrawerField('Cloudflare Token', 'password', draft.cloudflare_api_token, 'deploy.cloudflare_api_token')}
799
802
  ${renderDrawerField('Pages Secret ADMIN', 'password', draft.pages_secret_admin, 'deploy.pages_secret_admin')}
800
803
  </div>
@@ -946,6 +949,7 @@ export function buildSourceIterationDraft(sources = {}) {
946
949
  return {
947
950
  sources: structuredClone(sources),
948
951
  maxIterations: coercePositiveInteger(firstSource.max_iterations, 40),
952
+ plateauLimit: coercePositiveInteger(firstSource.plateau_limit, 20),
949
953
  areaMin: coerceAreaValue(firstSource.area_min, 0),
950
954
  areaMax: coerceAreaValue(firstSource.area_max, 100)
951
955
  };
@@ -1004,6 +1008,7 @@ export function applyAvailabilityTargetDraft(draft = {}) {
1004
1008
 
1005
1009
  export function applySourceIterationDraft(sources = {}, draft = {}) {
1006
1010
  const maxIterations = coercePositiveInteger(draft.maxIterations, 40);
1011
+ const plateauLimit = coercePositiveInteger(draft.plateauLimit, 20);
1007
1012
  const areaMin = coerceAreaValue(draft.areaMin, 0);
1008
1013
  const areaMax = coerceAreaValue(draft.areaMax, 100);
1009
1014
  return Object.fromEntries(
@@ -1013,6 +1018,7 @@ export function applySourceIterationDraft(sources = {}, draft = {}) {
1013
1018
  ...source,
1014
1019
  max_iterations: maxIterations,
1015
1020
  min_iterations: Math.min(coercePositiveInteger(source.min_iterations, 0), maxIterations),
1021
+ plateau_limit: plateauLimit,
1016
1022
  area_min: Math.min(areaMin, areaMax),
1017
1023
  area_max: Math.max(areaMin, areaMax)
1018
1024
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@swimmingliu/autovpn",
3
- "version": "1.6.1",
3
+ "version": "1.6.3",
4
4
  "description": "npm wrapper for the AutoVPN headless CLI",
5
5
  "type": "module",
6
6
  "repository": {