From 7cd32910d92e8cb0bc3eae3cba6b04c007cd16ac Mon Sep 17 00:00:00 2001 From: divocat Date: Tue, 14 Oct 2025 22:11:10 +0300 Subject: [PATCH] refactor: reorganize styles --- .../src/icons/renderLoaderCircleIcon24.ts | 2 +- .../src/podkop/tabs/dashboard/index.ts | 2 + .../src/podkop/tabs/dashboard/styles.ts | 120 ++ .../src/podkop/tabs/diagnostic/index.ts | 2 + .../src/podkop/tabs/diagnostic/styles.ts | 142 ++ fe-app-podkop/src/styles.ts | 315 +---- .../src/validators/validateVlessUrl.ts | 2 +- .../luci-static/resources/view/podkop/main.js | 1213 ++++++++--------- 8 files changed, 887 insertions(+), 911 deletions(-) create mode 100644 fe-app-podkop/src/podkop/tabs/dashboard/styles.ts create mode 100644 fe-app-podkop/src/podkop/tabs/diagnostic/styles.ts diff --git a/fe-app-podkop/src/icons/renderLoaderCircleIcon24.ts b/fe-app-podkop/src/icons/renderLoaderCircleIcon24.ts index 43e2030..927964d 100644 --- a/fe-app-podkop/src/icons/renderLoaderCircleIcon24.ts +++ b/fe-app-podkop/src/icons/renderLoaderCircleIcon24.ts @@ -14,7 +14,7 @@ export function renderLoaderCircleIcon24() { 'stroke-width': '2', 'stroke-linecap': 'round', 'stroke-linejoin': 'round', - class: 'lucide lucide-loader-circle lucide-rotate', + class: 'lucide lucide-loader-circle rotate', }, [ svgEl('path', { diff --git a/fe-app-podkop/src/podkop/tabs/dashboard/index.ts b/fe-app-podkop/src/podkop/tabs/dashboard/index.ts index 105b142..7540731 100644 --- a/fe-app-podkop/src/podkop/tabs/dashboard/index.ts +++ b/fe-app-podkop/src/podkop/tabs/dashboard/index.ts @@ -1,7 +1,9 @@ import { render } from './render'; import { initController } from './initController'; +import { styles } from './styles'; export const DashboardTab = { render, initController, + styles, }; diff --git a/fe-app-podkop/src/podkop/tabs/dashboard/styles.ts b/fe-app-podkop/src/podkop/tabs/dashboard/styles.ts new file mode 100644 index 0000000..32066e5 --- /dev/null +++ b/fe-app-podkop/src/podkop/tabs/dashboard/styles.ts @@ -0,0 +1,120 @@ +// language=CSS +export const styles = ` +#cbi-podkop-dashboard-_mount_node > div { + width: 100%; +} + +#cbi-podkop-dashboard > h3 { + display: none; +} + +.pdk_dashboard-page { + width: 100%; + --dashboard-grid-columns: 4; +} + +@media (max-width: 900px) { + .pdk_dashboard-page { + --dashboard-grid-columns: 2; + } +} + +.pdk_dashboard-page__widgets-section { + margin-top: 10px; + display: grid; + grid-template-columns: repeat(var(--dashboard-grid-columns), 1fr); + grid-gap: 10px; +} + +.pdk_dashboard-page__widgets-section__item { + border: 2px var(--background-color-low, lightgray) solid; + border-radius: 4px; + padding: 10px; +} + +.pdk_dashboard-page__widgets-section__item__title {} + +.pdk_dashboard-page__widgets-section__item__row {} + +.pdk_dashboard-page__widgets-section__item__row--success .pdk_dashboard-page__widgets-section__item__row__value { + color: var(--success-color-medium, green); +} + +.pdk_dashboard-page__widgets-section__item__row--error .pdk_dashboard-page__widgets-section__item__row__value { + color: var(--error-color-medium, red); +} + +.pdk_dashboard-page__widgets-section__item__row__key {} + +.pdk_dashboard-page__widgets-section__item__row__value {} + +.pdk_dashboard-page__outbound-section { + margin-top: 10px; + border: 2px var(--background-color-low, lightgray) solid; + border-radius: 4px; + padding: 10px; +} + +.pdk_dashboard-page__outbound-section__title-section { + display: flex; + align-items: center; + justify-content: space-between; +} + +.pdk_dashboard-page__outbound-section__title-section__title { + color: var(--text-color-high); + font-weight: 700; +} + +.pdk_dashboard-page__outbound-grid { + margin-top: 5px; + display: grid; + grid-template-columns: repeat(var(--dashboard-grid-columns), 1fr); + grid-gap: 10px; +} + +.pdk_dashboard-page__outbound-grid__item { + border: 2px var(--background-color-low, lightgray) solid; + border-radius: 4px; + padding: 10px; + transition: border 0.2s ease; +} + +.pdk_dashboard-page__outbound-grid__item--selectable { + cursor: pointer; +} + +.pdk_dashboard-page__outbound-grid__item--selectable:hover { + border-color: var(--primary-color-high, dodgerblue); +} + +.pdk_dashboard-page__outbound-grid__item--active { + border-color: var(--success-color-medium, green); +} + +.pdk_dashboard-page__outbound-grid__item__footer { + display: flex; + align-items: center; + justify-content: space-between; + margin-top: 10px; +} + +.pdk_dashboard-page__outbound-grid__item__type {} + +.pdk_dashboard-page__outbound-grid__item__latency--empty { + color: var(--primary-color-low, lightgray); +} + +.pdk_dashboard-page__outbound-grid__item__latency--green { + color: var(--success-color-medium, green); +} + +.pdk_dashboard-page__outbound-grid__item__latency--yellow { + color: var(--warn-color-medium, orange); +} + +.pdk_dashboard-page__outbound-grid__item__latency--red { + color: var(--error-color-medium, red); +} + +`; diff --git a/fe-app-podkop/src/podkop/tabs/diagnostic/index.ts b/fe-app-podkop/src/podkop/tabs/diagnostic/index.ts index ce38706..2275b00 100644 --- a/fe-app-podkop/src/podkop/tabs/diagnostic/index.ts +++ b/fe-app-podkop/src/podkop/tabs/diagnostic/index.ts @@ -1,7 +1,9 @@ import { render } from './renderDiagnostic'; import { initController } from './initController'; +import { styles } from './styles'; export const DiagnosticTab = { render, initController, + styles, }; diff --git a/fe-app-podkop/src/podkop/tabs/diagnostic/styles.ts b/fe-app-podkop/src/podkop/tabs/diagnostic/styles.ts new file mode 100644 index 0000000..7fe2c21 --- /dev/null +++ b/fe-app-podkop/src/podkop/tabs/diagnostic/styles.ts @@ -0,0 +1,142 @@ +// language=CSS +export const styles = ` + +#cbi-podkop-diagnostic-_mount_node > div { + width: 100%; +} + +#cbi-podkop-diagnostic > h3 { + display: none; +} + +.pdk_diagnostic-page { + display: grid; + grid-template-columns: 2fr 1fr; + grid-column-gap: 10px; + align-items: start; +} + +.pdk_diagnostic-page__right-bar { + display: grid; + grid-template-columns: 1fr; + grid-row-gap: 10px; +} + +.pdk_diagnostic-page__right-bar__actions { + border: 2px var(--background-color-low, lightgray) solid; + border-radius: 4px; + padding: 10px; + + display: grid; + grid-template-columns: auto; + grid-row-gap: 10px; + +} + +.pdk_diagnostic-page__right-bar__system-info { + border: 2px var(--background-color-low, lightgray) solid; + border-radius: 4px; + padding: 10px; + + display: grid; + grid-template-columns: auto; + grid-row-gap: 10px; +} + +.pdk_diagnostic-page__right-bar__system-info__title { + +} + +.pdk_diagnostic-page__right-bar__system-info__row { + display: grid; + grid-template-columns: auto 1fr; + grid-column-gap: 5px; +} + +.pdk_diagnostic-page__left-bar { + display: grid; + grid-template-columns: 1fr; + grid-row-gap: 10px; +} + +.pdk_diagnostic-page__run_check_wrapper {} + +.pdk_diagnostic-page__run_check_wrapper button { + width: 100%; +} + +.pdk_diagnostic-page__checks { + display: grid; + grid-template-columns: 1fr; + grid-row-gap: 10px; +} + +.pdk_diagnostic_alert { + border: 2px var(--background-color-low, lightgray) solid; + border-radius: 4px; + + display: grid; + grid-template-columns: 24px 1fr; + grid-column-gap: 10px; + align-items: center; + padding: 10px; +} + +.pdk_diagnostic_alert--loading { + border: 2px var(--primary-color-high, dodgerblue) solid; +} + +.pdk_diagnostic_alert--warning { + border: 2px var(--warn-color-medium, orange) solid; + color: var(--warn-color-medium, orange); +} + +.pdk_diagnostic_alert--error { + border: 2px var(--error-color-medium, red) solid; + color: var(--error-color-medium, red); +} + +.pdk_diagnostic_alert--success { + border: 2px var(--success-color-medium, green) solid; + color: var(--success-color-medium, green); +} + +.pdk_diagnostic_alert--skipped {} + +.pdk_diagnostic_alert__icon {} + +.pdk_diagnostic_alert__content {} + +.pdk_diagnostic_alert__title { + display: block; +} + +.pdk_diagnostic_alert__description {} + +.pdk_diagnostic_alert__summary { + margin-top: 10px; +} + +.pdk_diagnostic_alert__summary__item { + display: grid; + grid-template-columns: 16px auto 1fr; + grid-column-gap: 10px; +} + +.pdk_diagnostic_alert__summary__item--error { + color: var(--error-color-medium, red); +} + +.pdk_diagnostic_alert__summary__item--warning { + color: var(--warn-color-medium, orange); +} + +.pdk_diagnostic_alert__summary__item--success { + color: var(--success-color-medium, green); +} + +.pdk_diagnostic_alert__summary__item__icon { + width: 16px; + height: 16px; +} +`; diff --git a/fe-app-podkop/src/styles.ts b/fe-app-podkop/src/styles.ts index 4b240bf..2518fd8 100644 --- a/fe-app-podkop/src/styles.ts +++ b/fe-app-podkop/src/styles.ts @@ -1,174 +1,43 @@ // language=CSS +import { DashboardTab, DiagnosticTab } from './podkop'; + export const GlobalStyles = ` -.cbi-value { - margin-bottom: 10px !important; -} +${DashboardTab.styles} +${DiagnosticTab.styles} -#diagnostics-status .table > div { - background: var(--background-color-primary); - border: 1px solid var(--border-color-medium); - border-radius: var(--border-radius); -} - -#diagnostics-status .table > div pre, -#diagnostics-status .table > div div[style*="monospace"] { - color: var(--color-text-primary); -} - -#diagnostics-status .alert-message { - background: var(--background-color-primary); - border-color: var(--border-color-medium); -} - -#cbi-podkop:has(.cbi-tab-disabled[data-tab="basic"]) #cbi-podkop-extra { - display: none; -} - -#cbi-podkop-dashboard-_mount_node > div { - width: 100%; -} - -#cbi-podkop-dashboard > h3 { - display: none; -} +/* Hide extra H3 for settings tab */ #cbi-podkop-settings > h3 { display: none; } +/* Hide extra H3 for sections tab */ #cbi-podkop-section > h3:nth-child(1) { display: none; } -#cbi-podkop-diagnostic > h3 { - display: none; -} - -.cbi-section-remove { +/* Vertical align for remove section action button */ +#cbi-podkop-section > .cbi-section-remove { margin-bottom: -32px; } -.cbi-value { - margin-bottom: 20px !important; -} - -/* Dashboard styles */ - -.pdk_dashboard-page { - width: 100%; - --dashboard-grid-columns: 4; -} - -@media (max-width: 900px) { - .pdk_dashboard-page { - --dashboard-grid-columns: 2; - } -} - -.pdk_dashboard-page__widgets-section { - margin-top: 10px; - display: grid; - grid-template-columns: repeat(var(--dashboard-grid-columns), 1fr); - grid-gap: 10px; -} - -.pdk_dashboard-page__widgets-section__item { - border: 2px var(--background-color-low, lightgray) solid; - border-radius: 4px; - padding: 10px; -} - -.pdk_dashboard-page__widgets-section__item__title {} - -.pdk_dashboard-page__widgets-section__item__row {} - -.pdk_dashboard-page__widgets-section__item__row--success .pdk_dashboard-page__widgets-section__item__row__value { - color: var(--success-color-medium, green); -} - -.pdk_dashboard-page__widgets-section__item__row--error .pdk_dashboard-page__widgets-section__item__row__value { - color: var(--error-color-medium, red); -} - -.pdk_dashboard-page__widgets-section__item__row__key {} - -.pdk_dashboard-page__widgets-section__item__row__value {} - -.pdk_dashboard-page__outbound-section { - margin-top: 10px; - border: 2px var(--background-color-low, lightgray) solid; - border-radius: 4px; - padding: 10px; -} - -.pdk_dashboard-page__outbound-section__title-section { - display: flex; - align-items: center; - justify-content: space-between; -} - -.pdk_dashboard-page__outbound-section__title-section__title { - color: var(--text-color-high); - font-weight: 700; -} - -.pdk_dashboard-page__outbound-grid { - margin-top: 5px; - display: grid; - grid-template-columns: repeat(var(--dashboard-grid-columns), 1fr); - grid-gap: 10px; -} - -.pdk_dashboard-page__outbound-grid__item { - border: 2px var(--background-color-low, lightgray) solid; - border-radius: 4px; - padding: 10px; - transition: border 0.2s ease; -} - -.pdk_dashboard-page__outbound-grid__item--selectable { - cursor: pointer; -} - -.pdk_dashboard-page__outbound-grid__item--selectable:hover { - border-color: var(--primary-color-high, dodgerblue); -} - -.pdk_dashboard-page__outbound-grid__item--active { - border-color: var(--success-color-medium, green); -} - -.pdk_dashboard-page__outbound-grid__item__footer { - display: flex; - align-items: center; - justify-content: space-between; - margin-top: 10px; -} - -.pdk_dashboard-page__outbound-grid__item__type {} - -.pdk_dashboard-page__outbound-grid__item__latency--empty { - color: var(--primary-color-low, lightgray); -} - -.pdk_dashboard-page__outbound-grid__item__latency--green { - color: var(--success-color-medium, green); -} - -.pdk_dashboard-page__outbound-grid__item__latency--yellow { - color: var(--warn-color-medium, orange); -} - -.pdk_dashboard-page__outbound-grid__item__latency--red { - color: var(--error-color-medium, red); -} - +/* Centered class helper */ .centered { display: flex; align-items: center; justify-content: center; } +/* Rotate class helper */ +.rotate { + animation: spin 1s linear infinite; +} + +@keyframes spin { + from { transform: rotate(0deg); } + to { transform: rotate(360deg); } +} + /* Skeleton styles*/ .skeleton { background-color: var(--background-color-low, #e0e0e0); @@ -198,150 +67,4 @@ export const GlobalStyles = ` left: 150%; } } - -/* Lucide spinner animate */ -.lucide-rotate { - animation: spin 1s linear infinite; -} - -@keyframes spin { - from { transform: rotate(0deg); } - to { transform: rotate(360deg); } -} - -#cbi-podkop-diagnostic-_mount_node > div { - width: 100%; -} - -.pdk_diagnostic-page { - display: grid; - grid-template-columns: 2fr 1fr; - grid-column-gap: 10px; - align-items: start; -} - -.pdk_diagnostic-page__right-bar { - display: grid; - grid-template-columns: 1fr; - grid-row-gap: 10px; -} - -.pdk_diagnostic-page__right-bar__actions { - border: 2px var(--background-color-low, lightgray) solid; - border-radius: 4px; - padding: 10px; - - display: grid; - grid-template-columns: auto; - grid-row-gap: 10px; - -} - -.pdk_diagnostic-page__right-bar__system-info { - border: 2px var(--background-color-low, lightgray) solid; - border-radius: 4px; - padding: 10px; - - display: grid; - grid-template-columns: auto; - grid-row-gap: 10px; -} - -.pdk_diagnostic-page__right-bar__system-info__title { - -} - -.pdk_diagnostic-page__right-bar__system-info__row { - display: grid; - grid-template-columns: auto 1fr; - grid-column-gap: 5px; -} - -.pdk_diagnostic-page__left-bar { - display: grid; - grid-template-columns: 1fr; - grid-row-gap: 10px; -} - -.pdk_diagnostic-page__run_check_wrapper {} - -.pdk_diagnostic-page__run_check_wrapper button { - width: 100%; -} - -.pdk_diagnostic-page__checks { - display: grid; - grid-template-columns: 1fr; - grid-row-gap: 10px; -} - -.pdk_diagnostic_alert { - border: 2px var(--background-color-low, lightgray) solid; - border-radius: 4px; - - display: grid; - grid-template-columns: 24px 1fr; - grid-column-gap: 10px; - align-items: center; - padding: 10px; -} - -.pdk_diagnostic_alert--loading { - border: 2px var(--primary-color-high, dodgerblue) solid; -} - -.pdk_diagnostic_alert--warning { - border: 2px var(--warn-color-medium, orange) solid; - color: var(--warn-color-medium, orange); -} - -.pdk_diagnostic_alert--error { - border: 2px var(--error-color-medium, red) solid; - color: var(--error-color-medium, red); -} - -.pdk_diagnostic_alert--success { - border: 2px var(--success-color-medium, green) solid; - color: var(--success-color-medium, green); -} - -.pdk_diagnostic_alert--skipped {} - -.pdk_diagnostic_alert__icon {} - -.pdk_diagnostic_alert__content {} - -.pdk_diagnostic_alert__title { - display: block; -} - -.pdk_diagnostic_alert__description {} - -.pdk_diagnostic_alert__summary { - margin-top: 10px; -} - -.pdk_diagnostic_alert__summary__item { - display: grid; - grid-template-columns: 16px auto 1fr; - grid-column-gap: 10px; -} - -.pdk_diagnostic_alert__summary__item--error { - color: var(--error-color-medium, red); -} - -.pdk_diagnostic_alert__summary__item--warning { - color: var(--warn-color-medium, orange); -} - -.pdk_diagnostic_alert__summary__item--success { - color: var(--success-color-medium, green); -} - -.pdk_diagnostic_alert__summary__item__icon { - width: 16px; - height: 16px; -} - `; diff --git a/fe-app-podkop/src/validators/validateVlessUrl.ts b/fe-app-podkop/src/validators/validateVlessUrl.ts index 06a84ba..23cebc9 100644 --- a/fe-app-podkop/src/validators/validateVlessUrl.ts +++ b/fe-app-podkop/src/validators/validateVlessUrl.ts @@ -1,5 +1,5 @@ import { ValidationResult } from './types'; -import { parseQueryString } from '../helpers'; +import { parseQueryString } from '../helpers/parseQueryString'; export function validateVlessUrl(url: string): ValidationResult { try { diff --git a/luci-app-podkop/htdocs/luci-static/resources/view/podkop/main.js b/luci-app-podkop/htdocs/luci-static/resources/view/podkop/main.js index 7ef6f9a..08517ae 100644 --- a/luci-app-podkop/htdocs/luci-static/resources/view/podkop/main.js +++ b/luci-app-podkop/htdocs/luci-static/resources/view/podkop/main.js @@ -210,597 +210,6 @@ function validateShadowsocksUrl(url) { return { valid: true, message: _("Valid") }; } -// src/helpers/getBaseUrl.ts -function getBaseUrl() { - const { protocol, hostname } = window.location; - return `${protocol}//${hostname}`; -} - -// src/helpers/parseValueList.ts -function parseValueList(value) { - return value.split(/\n/).map((line) => line.split("//")[0]).join(" ").split(/[,\s]+/).map((s) => s.trim()).filter(Boolean); -} - -// src/styles.ts -var GlobalStyles = ` -.cbi-value { - margin-bottom: 10px !important; -} - -#diagnostics-status .table > div { - background: var(--background-color-primary); - border: 1px solid var(--border-color-medium); - border-radius: var(--border-radius); -} - -#diagnostics-status .table > div pre, -#diagnostics-status .table > div div[style*="monospace"] { - color: var(--color-text-primary); -} - -#diagnostics-status .alert-message { - background: var(--background-color-primary); - border-color: var(--border-color-medium); -} - -#cbi-podkop:has(.cbi-tab-disabled[data-tab="basic"]) #cbi-podkop-extra { - display: none; -} - -#cbi-podkop-dashboard-_mount_node > div { - width: 100%; -} - -#cbi-podkop-dashboard > h3 { - display: none; -} - -#cbi-podkop-settings > h3 { - display: none; -} - -#cbi-podkop-section > h3:nth-child(1) { - display: none; -} - -#cbi-podkop-diagnostic > h3 { - display: none; -} - -.cbi-section-remove { - margin-bottom: -32px; -} - -.cbi-value { - margin-bottom: 20px !important; -} - -/* Dashboard styles */ - -.pdk_dashboard-page { - width: 100%; - --dashboard-grid-columns: 4; -} - -@media (max-width: 900px) { - .pdk_dashboard-page { - --dashboard-grid-columns: 2; - } -} - -.pdk_dashboard-page__widgets-section { - margin-top: 10px; - display: grid; - grid-template-columns: repeat(var(--dashboard-grid-columns), 1fr); - grid-gap: 10px; -} - -.pdk_dashboard-page__widgets-section__item { - border: 2px var(--background-color-low, lightgray) solid; - border-radius: 4px; - padding: 10px; -} - -.pdk_dashboard-page__widgets-section__item__title {} - -.pdk_dashboard-page__widgets-section__item__row {} - -.pdk_dashboard-page__widgets-section__item__row--success .pdk_dashboard-page__widgets-section__item__row__value { - color: var(--success-color-medium, green); -} - -.pdk_dashboard-page__widgets-section__item__row--error .pdk_dashboard-page__widgets-section__item__row__value { - color: var(--error-color-medium, red); -} - -.pdk_dashboard-page__widgets-section__item__row__key {} - -.pdk_dashboard-page__widgets-section__item__row__value {} - -.pdk_dashboard-page__outbound-section { - margin-top: 10px; - border: 2px var(--background-color-low, lightgray) solid; - border-radius: 4px; - padding: 10px; -} - -.pdk_dashboard-page__outbound-section__title-section { - display: flex; - align-items: center; - justify-content: space-between; -} - -.pdk_dashboard-page__outbound-section__title-section__title { - color: var(--text-color-high); - font-weight: 700; -} - -.pdk_dashboard-page__outbound-grid { - margin-top: 5px; - display: grid; - grid-template-columns: repeat(var(--dashboard-grid-columns), 1fr); - grid-gap: 10px; -} - -.pdk_dashboard-page__outbound-grid__item { - border: 2px var(--background-color-low, lightgray) solid; - border-radius: 4px; - padding: 10px; - transition: border 0.2s ease; -} - -.pdk_dashboard-page__outbound-grid__item--selectable { - cursor: pointer; -} - -.pdk_dashboard-page__outbound-grid__item--selectable:hover { - border-color: var(--primary-color-high, dodgerblue); -} - -.pdk_dashboard-page__outbound-grid__item--active { - border-color: var(--success-color-medium, green); -} - -.pdk_dashboard-page__outbound-grid__item__footer { - display: flex; - align-items: center; - justify-content: space-between; - margin-top: 10px; -} - -.pdk_dashboard-page__outbound-grid__item__type {} - -.pdk_dashboard-page__outbound-grid__item__latency--empty { - color: var(--primary-color-low, lightgray); -} - -.pdk_dashboard-page__outbound-grid__item__latency--green { - color: var(--success-color-medium, green); -} - -.pdk_dashboard-page__outbound-grid__item__latency--yellow { - color: var(--warn-color-medium, orange); -} - -.pdk_dashboard-page__outbound-grid__item__latency--red { - color: var(--error-color-medium, red); -} - -.centered { - display: flex; - align-items: center; - justify-content: center; -} - -/* Skeleton styles*/ -.skeleton { - background-color: var(--background-color-low, #e0e0e0); - border-radius: 4px; - position: relative; - overflow: hidden; -} - -.skeleton::after { - content: ''; - position: absolute; - top: 0; - left: -150%; - width: 150%; - height: 100%; - background: linear-gradient( - 90deg, - transparent, - rgba(255, 255, 255, 0.4), - transparent - ); - animation: skeleton-shimmer 1.6s infinite; -} - -@keyframes skeleton-shimmer { - 100% { - left: 150%; - } -} - -/* Lucide spinner animate */ -.lucide-rotate { - animation: spin 1s linear infinite; -} - -@keyframes spin { - from { transform: rotate(0deg); } - to { transform: rotate(360deg); } -} - -#cbi-podkop-diagnostic-_mount_node > div { - width: 100%; -} - -.pdk_diagnostic-page { - display: grid; - grid-template-columns: 2fr 1fr; - grid-column-gap: 10px; - align-items: start; -} - -.pdk_diagnostic-page__right-bar { - display: grid; - grid-template-columns: 1fr; - grid-row-gap: 10px; -} - -.pdk_diagnostic-page__right-bar__actions { - border: 2px var(--background-color-low, lightgray) solid; - border-radius: 4px; - padding: 10px; - - display: grid; - grid-template-columns: auto; - grid-row-gap: 10px; - -} - -.pdk_diagnostic-page__right-bar__system-info { - border: 2px var(--background-color-low, lightgray) solid; - border-radius: 4px; - padding: 10px; - - display: grid; - grid-template-columns: auto; - grid-row-gap: 10px; -} - -.pdk_diagnostic-page__right-bar__system-info__title { - -} - -.pdk_diagnostic-page__right-bar__system-info__row { - display: grid; - grid-template-columns: auto 1fr; - grid-column-gap: 5px; -} - -.pdk_diagnostic-page__left-bar { - display: grid; - grid-template-columns: 1fr; - grid-row-gap: 10px; -} - -.pdk_diagnostic-page__run_check_wrapper {} - -.pdk_diagnostic-page__run_check_wrapper button { - width: 100%; -} - -.pdk_diagnostic-page__checks { - display: grid; - grid-template-columns: 1fr; - grid-row-gap: 10px; -} - -.pdk_diagnostic_alert { - border: 2px var(--background-color-low, lightgray) solid; - border-radius: 4px; - - display: grid; - grid-template-columns: 24px 1fr; - grid-column-gap: 10px; - align-items: center; - padding: 10px; -} - -.pdk_diagnostic_alert--loading { - border: 2px var(--primary-color-high, dodgerblue) solid; -} - -.pdk_diagnostic_alert--warning { - border: 2px var(--warn-color-medium, orange) solid; - color: var(--warn-color-medium, orange); -} - -.pdk_diagnostic_alert--error { - border: 2px var(--error-color-medium, red) solid; - color: var(--error-color-medium, red); -} - -.pdk_diagnostic_alert--success { - border: 2px var(--success-color-medium, green) solid; - color: var(--success-color-medium, green); -} - -.pdk_diagnostic_alert--skipped {} - -.pdk_diagnostic_alert__icon {} - -.pdk_diagnostic_alert__content {} - -.pdk_diagnostic_alert__title { - display: block; -} - -.pdk_diagnostic_alert__description {} - -.pdk_diagnostic_alert__summary { - margin-top: 10px; -} - -.pdk_diagnostic_alert__summary__item { - display: grid; - grid-template-columns: 16px auto 1fr; - grid-column-gap: 10px; -} - -.pdk_diagnostic_alert__summary__item--error { - color: var(--error-color-medium, red); -} - -.pdk_diagnostic_alert__summary__item--warning { - color: var(--warn-color-medium, orange); -} - -.pdk_diagnostic_alert__summary__item--success { - color: var(--success-color-medium, green); -} - -.pdk_diagnostic_alert__summary__item__icon { - width: 16px; - height: 16px; -} - -`; - -// src/helpers/injectGlobalStyles.ts -function injectGlobalStyles() { - document.head.insertAdjacentHTML( - "beforeend", - ` - - ` - ); -} - -// src/helpers/withTimeout.ts -async function withTimeout(promise, timeoutMs, operationName, timeoutMessage = _("Operation timed out")) { - let timeoutId; - const start = performance.now(); - const timeoutPromise = new Promise((_2, reject) => { - timeoutId = setTimeout(() => reject(new Error(timeoutMessage)), timeoutMs); - }); - try { - return await Promise.race([promise, timeoutPromise]); - } finally { - clearTimeout(timeoutId); - const elapsed = performance.now() - start; - console.log(`[${operationName}] Execution time: ${elapsed.toFixed(2)} ms`); - } -} - -// src/constants.ts -var STATUS_COLORS = { - SUCCESS: "#4caf50", - ERROR: "#f44336", - WARNING: "#ff9800" -}; -var PODKOP_LUCI_APP_VERSION = "__COMPILED_VERSION_VARIABLE__"; -var FAKEIP_CHECK_DOMAIN = "fakeip.podkop.fyi"; -var IP_CHECK_DOMAIN = "ip.podkop.fyi"; -var REGIONAL_OPTIONS = [ - "russia_inside", - "russia_outside", - "ukraine_inside" -]; -var ALLOWED_WITH_RUSSIA_INSIDE = [ - "russia_inside", - "meta", - "twitter", - "discord", - "telegram", - "cloudflare", - "google_ai", - "google_play", - "hetzner", - "ovh", - "hodca", - "digitalocean", - "cloudfront" -]; -var DOMAIN_LIST_OPTIONS = { - russia_inside: "Russia inside", - russia_outside: "Russia outside", - ukraine_inside: "Ukraine", - geoblock: "Geo Block", - block: "Block", - porn: "Porn", - news: "News", - anime: "Anime", - youtube: "Youtube", - discord: "Discord", - meta: "Meta", - twitter: "Twitter (X)", - hdrezka: "HDRezka", - tiktok: "Tik-Tok", - telegram: "Telegram", - cloudflare: "Cloudflare", - google_ai: "Google AI", - google_play: "Google Play", - hodca: "H.O.D.C.A", - hetzner: "Hetzner ASN", - ovh: "OVH ASN", - digitalocean: "Digital Ocean ASN", - cloudfront: "CloudFront ASN" -}; -var UPDATE_INTERVAL_OPTIONS = { - "1h": "Every hour", - "3h": "Every 3 hours", - "12h": "Every 12 hours", - "1d": "Every day", - "3d": "Every 3 days" -}; -var DNS_SERVER_OPTIONS = { - "1.1.1.1": "1.1.1.1 (Cloudflare)", - "8.8.8.8": "8.8.8.8 (Google)", - "9.9.9.9": "9.9.9.9 (Quad9)", - "dns.adguard-dns.com": "dns.adguard-dns.com (AdGuard Default)", - "unfiltered.adguard-dns.com": "unfiltered.adguard-dns.com (AdGuard Unfiltered)", - "family.adguard-dns.com": "family.adguard-dns.com (AdGuard Family)" -}; -var BOOTSTRAP_DNS_SERVER_OPTIONS = { - "77.88.8.8": "77.88.8.8 (Yandex DNS)", - "77.88.8.1": "77.88.8.1 (Yandex DNS)", - "1.1.1.1": "1.1.1.1 (Cloudflare DNS)", - "1.0.0.1": "1.0.0.1 (Cloudflare DNS)", - "8.8.8.8": "8.8.8.8 (Google DNS)", - "8.8.4.4": "8.8.4.4 (Google DNS)", - "9.9.9.9": "9.9.9.9 (Quad9 DNS)", - "9.9.9.11": "9.9.9.11 (Quad9 DNS)" -}; -var DIAGNOSTICS_UPDATE_INTERVAL = 1e4; -var CACHE_TIMEOUT = DIAGNOSTICS_UPDATE_INTERVAL - 1e3; -var ERROR_POLL_INTERVAL = 1e4; -var COMMAND_TIMEOUT = 1e4; -var FETCH_TIMEOUT = 1e4; -var BUTTON_FEEDBACK_TIMEOUT = 1e3; -var DIAGNOSTICS_INITIAL_DELAY = 100; -var COMMAND_SCHEDULING = { - P0_PRIORITY: 0, - // Highest priority (no delay) - P1_PRIORITY: 100, - // Very high priority - P2_PRIORITY: 300, - // High priority - P3_PRIORITY: 500, - // Above average - P4_PRIORITY: 700, - // Standard priority - P5_PRIORITY: 900, - // Below average - P6_PRIORITY: 1100, - // Low priority - P7_PRIORITY: 1300, - // Very low priority - P8_PRIORITY: 1500, - // Background execution - P9_PRIORITY: 1700, - // Idle mode execution - P10_PRIORITY: 1900 - // Lowest priority -}; - -// src/helpers/executeShellCommand.ts -async function executeShellCommand({ - command, - args, - timeout = COMMAND_TIMEOUT -}) { - try { - return withTimeout( - fs.exec(command, args), - timeout, - [command, ...args].join(" ") - ); - } catch (err) { - const error = err; - return { stdout: "", stderr: error?.message, code: 0 }; - } -} - -// src/helpers/maskIP.ts -function maskIP(ip = "") { - const ipv4Regex = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/; - return ip.replace(ipv4Regex, (_match, _p1, _p2, _p3, p4) => `XX.XX.XX.${p4}`); -} - -// src/helpers/getProxyUrlName.ts -function getProxyUrlName(url) { - try { - const [_link, hash] = url.split("#"); - if (!hash) { - return ""; - } - return decodeURIComponent(hash); - } catch { - return ""; - } -} - -// src/helpers/onMount.ts -async function onMount(id) { - return new Promise((resolve) => { - const el = document.getElementById(id); - if (el && el.offsetParent !== null) { - return resolve(el); - } - const observer = new MutationObserver(() => { - const target = document.getElementById(id); - if (target) { - const io = new IntersectionObserver((entries) => { - const visible = entries.some((e) => e.isIntersecting); - if (visible) { - observer.disconnect(); - io.disconnect(); - resolve(target); - } - }); - io.observe(target); - } - }); - observer.observe(document.body, { - childList: true, - subtree: true - }); - }); -} - -// src/helpers/getClashApiUrl.ts -function getClashApiUrl() { - const { hostname } = window.location; - return `http://${hostname}:9090`; -} -function getClashWsUrl() { - const { hostname } = window.location; - return `ws://${hostname}:9090`; -} -function getClashUIUrl() { - const { hostname } = window.location; - return `http://${hostname}:9090/ui`; -} - -// src/helpers/splitProxyString.ts -function splitProxyString(str) { - return str.split("\n").map((line) => line.trim()).filter((line) => !line.startsWith("//")).filter(Boolean); -} - -// src/helpers/preserveScrollForPage.ts -function preserveScrollForPage(renderFn) { - const scrollY = window.scrollY; - renderFn(); - requestAnimationFrame(() => { - window.scrollTo({ top: scrollY }); - }); -} - // src/helpers/parseQueryString.ts function parseQueryString(query) { const clean = query.startsWith("?") ? query.slice(1) : query; @@ -818,25 +227,6 @@ function parseQueryString(query) { ); } -// src/helpers/svgEl.ts -function svgEl(tag, attrs = {}, children = []) { - const NS = "http://www.w3.org/2000/svg"; - const el = document.createElementNS(NS, tag); - for (const [k, v] of Object.entries(attrs)) { - if (v != null) el.setAttribute(k, String(v)); - } - (Array.isArray(children) ? children : [children]).filter(Boolean).forEach((ch) => el.appendChild(ch)); - return el; -} - -// src/helpers/insertIf.ts -function insertIf(condition, elements) { - return condition ? elements : []; -} -function insertIfObj(condition, object) { - return condition ? object : {}; -} - // src/validators/validateVlessUrl.ts function validateVlessUrl(url) { try { @@ -1003,6 +393,17 @@ function validateProxyUrl(url) { }; } +// src/helpers/getBaseUrl.ts +function getBaseUrl() { + const { protocol, hostname } = window.location; + return `${protocol}//${hostname}`; +} + +// src/helpers/parseValueList.ts +function parseValueList(value) { + return value.split(/\n/).map((line) => line.split("//")[0]).join(" ").split(/[,\s]+/).map((s) => s.trim()).filter(Boolean); +} + // src/podkop/api.ts async function createBaseApiRequest(fetchFn, options) { const wrappedFn = () => options?.timeoutMs && options?.operationName ? withTimeout( @@ -1224,6 +625,117 @@ var CustomPodkopMethods = { getDashboardSections }; +// src/constants.ts +var STATUS_COLORS = { + SUCCESS: "#4caf50", + ERROR: "#f44336", + WARNING: "#ff9800" +}; +var PODKOP_LUCI_APP_VERSION = "__COMPILED_VERSION_VARIABLE__"; +var FAKEIP_CHECK_DOMAIN = "fakeip.podkop.fyi"; +var IP_CHECK_DOMAIN = "ip.podkop.fyi"; +var REGIONAL_OPTIONS = [ + "russia_inside", + "russia_outside", + "ukraine_inside" +]; +var ALLOWED_WITH_RUSSIA_INSIDE = [ + "russia_inside", + "meta", + "twitter", + "discord", + "telegram", + "cloudflare", + "google_ai", + "google_play", + "hetzner", + "ovh", + "hodca", + "digitalocean", + "cloudfront" +]; +var DOMAIN_LIST_OPTIONS = { + russia_inside: "Russia inside", + russia_outside: "Russia outside", + ukraine_inside: "Ukraine", + geoblock: "Geo Block", + block: "Block", + porn: "Porn", + news: "News", + anime: "Anime", + youtube: "Youtube", + discord: "Discord", + meta: "Meta", + twitter: "Twitter (X)", + hdrezka: "HDRezka", + tiktok: "Tik-Tok", + telegram: "Telegram", + cloudflare: "Cloudflare", + google_ai: "Google AI", + google_play: "Google Play", + hodca: "H.O.D.C.A", + hetzner: "Hetzner ASN", + ovh: "OVH ASN", + digitalocean: "Digital Ocean ASN", + cloudfront: "CloudFront ASN" +}; +var UPDATE_INTERVAL_OPTIONS = { + "1h": "Every hour", + "3h": "Every 3 hours", + "12h": "Every 12 hours", + "1d": "Every day", + "3d": "Every 3 days" +}; +var DNS_SERVER_OPTIONS = { + "1.1.1.1": "1.1.1.1 (Cloudflare)", + "8.8.8.8": "8.8.8.8 (Google)", + "9.9.9.9": "9.9.9.9 (Quad9)", + "dns.adguard-dns.com": "dns.adguard-dns.com (AdGuard Default)", + "unfiltered.adguard-dns.com": "unfiltered.adguard-dns.com (AdGuard Unfiltered)", + "family.adguard-dns.com": "family.adguard-dns.com (AdGuard Family)" +}; +var BOOTSTRAP_DNS_SERVER_OPTIONS = { + "77.88.8.8": "77.88.8.8 (Yandex DNS)", + "77.88.8.1": "77.88.8.1 (Yandex DNS)", + "1.1.1.1": "1.1.1.1 (Cloudflare DNS)", + "1.0.0.1": "1.0.0.1 (Cloudflare DNS)", + "8.8.8.8": "8.8.8.8 (Google DNS)", + "8.8.4.4": "8.8.4.4 (Google DNS)", + "9.9.9.9": "9.9.9.9 (Quad9 DNS)", + "9.9.9.11": "9.9.9.11 (Quad9 DNS)" +}; +var DIAGNOSTICS_UPDATE_INTERVAL = 1e4; +var CACHE_TIMEOUT = DIAGNOSTICS_UPDATE_INTERVAL - 1e3; +var ERROR_POLL_INTERVAL = 1e4; +var COMMAND_TIMEOUT = 1e4; +var FETCH_TIMEOUT = 1e4; +var BUTTON_FEEDBACK_TIMEOUT = 1e3; +var DIAGNOSTICS_INITIAL_DELAY = 100; +var COMMAND_SCHEDULING = { + P0_PRIORITY: 0, + // Highest priority (no delay) + P1_PRIORITY: 100, + // Very high priority + P2_PRIORITY: 300, + // High priority + P3_PRIORITY: 500, + // Above average + P4_PRIORITY: 700, + // Standard priority + P5_PRIORITY: 900, + // Below average + P6_PRIORITY: 1100, + // Low priority + P7_PRIORITY: 1300, + // Very low priority + P8_PRIORITY: 1500, + // Background execution + P9_PRIORITY: 1700, + // Idle mode execution + P10_PRIORITY: 1900 + // Lowest priority +}; + // src/podkop/methods/fakeip/getFakeIpCheck.ts async function getFakeIpCheck() { return createBaseApiRequest( @@ -2307,10 +1819,132 @@ async function initController() { }); } +// src/podkop/tabs/dashboard/styles.ts +var styles = ` +#cbi-podkop-dashboard-_mount_node > div { + width: 100%; +} + +#cbi-podkop-dashboard > h3 { + display: none; +} + +.pdk_dashboard-page { + width: 100%; + --dashboard-grid-columns: 4; +} + +@media (max-width: 900px) { + .pdk_dashboard-page { + --dashboard-grid-columns: 2; + } +} + +.pdk_dashboard-page__widgets-section { + margin-top: 10px; + display: grid; + grid-template-columns: repeat(var(--dashboard-grid-columns), 1fr); + grid-gap: 10px; +} + +.pdk_dashboard-page__widgets-section__item { + border: 2px var(--background-color-low, lightgray) solid; + border-radius: 4px; + padding: 10px; +} + +.pdk_dashboard-page__widgets-section__item__title {} + +.pdk_dashboard-page__widgets-section__item__row {} + +.pdk_dashboard-page__widgets-section__item__row--success .pdk_dashboard-page__widgets-section__item__row__value { + color: var(--success-color-medium, green); +} + +.pdk_dashboard-page__widgets-section__item__row--error .pdk_dashboard-page__widgets-section__item__row__value { + color: var(--error-color-medium, red); +} + +.pdk_dashboard-page__widgets-section__item__row__key {} + +.pdk_dashboard-page__widgets-section__item__row__value {} + +.pdk_dashboard-page__outbound-section { + margin-top: 10px; + border: 2px var(--background-color-low, lightgray) solid; + border-radius: 4px; + padding: 10px; +} + +.pdk_dashboard-page__outbound-section__title-section { + display: flex; + align-items: center; + justify-content: space-between; +} + +.pdk_dashboard-page__outbound-section__title-section__title { + color: var(--text-color-high); + font-weight: 700; +} + +.pdk_dashboard-page__outbound-grid { + margin-top: 5px; + display: grid; + grid-template-columns: repeat(var(--dashboard-grid-columns), 1fr); + grid-gap: 10px; +} + +.pdk_dashboard-page__outbound-grid__item { + border: 2px var(--background-color-low, lightgray) solid; + border-radius: 4px; + padding: 10px; + transition: border 0.2s ease; +} + +.pdk_dashboard-page__outbound-grid__item--selectable { + cursor: pointer; +} + +.pdk_dashboard-page__outbound-grid__item--selectable:hover { + border-color: var(--primary-color-high, dodgerblue); +} + +.pdk_dashboard-page__outbound-grid__item--active { + border-color: var(--success-color-medium, green); +} + +.pdk_dashboard-page__outbound-grid__item__footer { + display: flex; + align-items: center; + justify-content: space-between; + margin-top: 10px; +} + +.pdk_dashboard-page__outbound-grid__item__type {} + +.pdk_dashboard-page__outbound-grid__item__latency--empty { + color: var(--primary-color-low, lightgray); +} + +.pdk_dashboard-page__outbound-grid__item__latency--green { + color: var(--success-color-medium, green); +} + +.pdk_dashboard-page__outbound-grid__item__latency--yellow { + color: var(--warn-color-medium, orange); +} + +.pdk_dashboard-page__outbound-grid__item__latency--red { + color: var(--error-color-medium, red); +} + +`; + // src/podkop/tabs/dashboard/index.ts var DashboardTab = { render, - initController + initController, + styles }; // src/podkop/tabs/diagnostic/renderDiagnostic.ts @@ -2688,7 +2322,7 @@ function renderLoaderCircleIcon24() { "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", - class: "lucide lucide-loader-circle lucide-rotate" + class: "lucide lucide-loader-circle rotate" }, [ svgEl("path", { @@ -3194,11 +2828,364 @@ async function initController2() { }); } +// src/podkop/tabs/diagnostic/styles.ts +var styles2 = ` + +#cbi-podkop-diagnostic-_mount_node > div { + width: 100%; +} + +#cbi-podkop-diagnostic > h3 { + display: none; +} + +.pdk_diagnostic-page { + display: grid; + grid-template-columns: 2fr 1fr; + grid-column-gap: 10px; + align-items: start; +} + +.pdk_diagnostic-page__right-bar { + display: grid; + grid-template-columns: 1fr; + grid-row-gap: 10px; +} + +.pdk_diagnostic-page__right-bar__actions { + border: 2px var(--background-color-low, lightgray) solid; + border-radius: 4px; + padding: 10px; + + display: grid; + grid-template-columns: auto; + grid-row-gap: 10px; + +} + +.pdk_diagnostic-page__right-bar__system-info { + border: 2px var(--background-color-low, lightgray) solid; + border-radius: 4px; + padding: 10px; + + display: grid; + grid-template-columns: auto; + grid-row-gap: 10px; +} + +.pdk_diagnostic-page__right-bar__system-info__title { + +} + +.pdk_diagnostic-page__right-bar__system-info__row { + display: grid; + grid-template-columns: auto 1fr; + grid-column-gap: 5px; +} + +.pdk_diagnostic-page__left-bar { + display: grid; + grid-template-columns: 1fr; + grid-row-gap: 10px; +} + +.pdk_diagnostic-page__run_check_wrapper {} + +.pdk_diagnostic-page__run_check_wrapper button { + width: 100%; +} + +.pdk_diagnostic-page__checks { + display: grid; + grid-template-columns: 1fr; + grid-row-gap: 10px; +} + +.pdk_diagnostic_alert { + border: 2px var(--background-color-low, lightgray) solid; + border-radius: 4px; + + display: grid; + grid-template-columns: 24px 1fr; + grid-column-gap: 10px; + align-items: center; + padding: 10px; +} + +.pdk_diagnostic_alert--loading { + border: 2px var(--primary-color-high, dodgerblue) solid; +} + +.pdk_diagnostic_alert--warning { + border: 2px var(--warn-color-medium, orange) solid; + color: var(--warn-color-medium, orange); +} + +.pdk_diagnostic_alert--error { + border: 2px var(--error-color-medium, red) solid; + color: var(--error-color-medium, red); +} + +.pdk_diagnostic_alert--success { + border: 2px var(--success-color-medium, green) solid; + color: var(--success-color-medium, green); +} + +.pdk_diagnostic_alert--skipped {} + +.pdk_diagnostic_alert__icon {} + +.pdk_diagnostic_alert__content {} + +.pdk_diagnostic_alert__title { + display: block; +} + +.pdk_diagnostic_alert__description {} + +.pdk_diagnostic_alert__summary { + margin-top: 10px; +} + +.pdk_diagnostic_alert__summary__item { + display: grid; + grid-template-columns: 16px auto 1fr; + grid-column-gap: 10px; +} + +.pdk_diagnostic_alert__summary__item--error { + color: var(--error-color-medium, red); +} + +.pdk_diagnostic_alert__summary__item--warning { + color: var(--warn-color-medium, orange); +} + +.pdk_diagnostic_alert__summary__item--success { + color: var(--success-color-medium, green); +} + +.pdk_diagnostic_alert__summary__item__icon { + width: 16px; + height: 16px; +} +`; + // src/podkop/tabs/diagnostic/index.ts var DiagnosticTab = { render: render2, - initController: initController2 + initController: initController2, + styles: styles2 }; + +// src/styles.ts +var GlobalStyles = ` +${DashboardTab.styles} +${DiagnosticTab.styles} + + +/* Hide extra H3 for settings tab */ +#cbi-podkop-settings > h3 { + display: none; +} + +/* Hide extra H3 for sections tab */ +#cbi-podkop-section > h3:nth-child(1) { + display: none; +} + +/* Vertical align for remove section action button */ +#cbi-podkop-section > .cbi-section-remove { + margin-bottom: -32px; +} + +/* Centered class helper */ +.centered { + display: flex; + align-items: center; + justify-content: center; +} + +/* Rotate class helper */ +.rotate { + animation: spin 1s linear infinite; +} + +@keyframes spin { + from { transform: rotate(0deg); } + to { transform: rotate(360deg); } +} + +/* Skeleton styles*/ +.skeleton { + background-color: var(--background-color-low, #e0e0e0); + border-radius: 4px; + position: relative; + overflow: hidden; +} + +.skeleton::after { + content: ''; + position: absolute; + top: 0; + left: -150%; + width: 150%; + height: 100%; + background: linear-gradient( + 90deg, + transparent, + rgba(255, 255, 255, 0.4), + transparent + ); + animation: skeleton-shimmer 1.6s infinite; +} + +@keyframes skeleton-shimmer { + 100% { + left: 150%; + } +} +`; + +// src/helpers/injectGlobalStyles.ts +function injectGlobalStyles() { + document.head.insertAdjacentHTML( + "beforeend", + ` + + ` + ); +} + +// src/helpers/withTimeout.ts +async function withTimeout(promise, timeoutMs, operationName, timeoutMessage = _("Operation timed out")) { + let timeoutId; + const start = performance.now(); + const timeoutPromise = new Promise((_2, reject) => { + timeoutId = setTimeout(() => reject(new Error(timeoutMessage)), timeoutMs); + }); + try { + return await Promise.race([promise, timeoutPromise]); + } finally { + clearTimeout(timeoutId); + const elapsed = performance.now() - start; + console.log(`[${operationName}] Execution time: ${elapsed.toFixed(2)} ms`); + } +} + +// src/helpers/executeShellCommand.ts +async function executeShellCommand({ + command, + args, + timeout = COMMAND_TIMEOUT +}) { + try { + return withTimeout( + fs.exec(command, args), + timeout, + [command, ...args].join(" ") + ); + } catch (err) { + const error = err; + return { stdout: "", stderr: error?.message, code: 0 }; + } +} + +// src/helpers/maskIP.ts +function maskIP(ip = "") { + const ipv4Regex = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/; + return ip.replace(ipv4Regex, (_match, _p1, _p2, _p3, p4) => `XX.XX.XX.${p4}`); +} + +// src/helpers/getProxyUrlName.ts +function getProxyUrlName(url) { + try { + const [_link, hash] = url.split("#"); + if (!hash) { + return ""; + } + return decodeURIComponent(hash); + } catch { + return ""; + } +} + +// src/helpers/onMount.ts +async function onMount(id) { + return new Promise((resolve) => { + const el = document.getElementById(id); + if (el && el.offsetParent !== null) { + return resolve(el); + } + const observer = new MutationObserver(() => { + const target = document.getElementById(id); + if (target) { + const io = new IntersectionObserver((entries) => { + const visible = entries.some((e) => e.isIntersecting); + if (visible) { + observer.disconnect(); + io.disconnect(); + resolve(target); + } + }); + io.observe(target); + } + }); + observer.observe(document.body, { + childList: true, + subtree: true + }); + }); +} + +// src/helpers/getClashApiUrl.ts +function getClashApiUrl() { + const { hostname } = window.location; + return `http://${hostname}:9090`; +} +function getClashWsUrl() { + const { hostname } = window.location; + return `ws://${hostname}:9090`; +} +function getClashUIUrl() { + const { hostname } = window.location; + return `http://${hostname}:9090/ui`; +} + +// src/helpers/splitProxyString.ts +function splitProxyString(str) { + return str.split("\n").map((line) => line.trim()).filter((line) => !line.startsWith("//")).filter(Boolean); +} + +// src/helpers/preserveScrollForPage.ts +function preserveScrollForPage(renderFn) { + const scrollY = window.scrollY; + renderFn(); + requestAnimationFrame(() => { + window.scrollTo({ top: scrollY }); + }); +} + +// src/helpers/svgEl.ts +function svgEl(tag, attrs = {}, children = []) { + const NS = "http://www.w3.org/2000/svg"; + const el = document.createElementNS(NS, tag); + for (const [k, v] of Object.entries(attrs)) { + if (v != null) el.setAttribute(k, String(v)); + } + (Array.isArray(children) ? children : [children]).filter(Boolean).forEach((ch) => el.appendChild(ch)); + return el; +} + +// src/helpers/insertIf.ts +function insertIf(condition, elements) { + return condition ? elements : []; +} +function insertIfObj(condition, object) { + return condition ? object : {}; +} return baseclass.extend({ ALLOWED_WITH_RUSSIA_INSIDE, BOOTSTRAP_DNS_SERVER_OPTIONS,