mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-05-18 12:05:53 +00:00
refactor: remove legacy advancedJson state
This commit is contained in:
parent
05b68c3b13
commit
b79abc8bc9
1 changed files with 327 additions and 31 deletions
|
|
@ -70,8 +70,11 @@ const FLOW_OPTIONS = Object.values(TLS_FLOW_CONTROL);
|
||||||
const inbound = ref(null);
|
const inbound = ref(null);
|
||||||
const dbForm = ref(null);
|
const dbForm = ref(null);
|
||||||
const saving = ref(false);
|
const saving = ref(false);
|
||||||
const advancedJson = ref({ stream: '', sniffing: '', settings: '' });
|
const advancedStreamText = ref('');
|
||||||
|
const advancedSniffingText = ref('');
|
||||||
|
const advancedSettingsText = ref('');
|
||||||
const activeTabKey = ref('basic');
|
const activeTabKey = ref('basic');
|
||||||
|
const advancedSectionKey = ref('all');
|
||||||
// Cached default cert/key paths from /panel/setting/defaultSettings —
|
// Cached default cert/key paths from /panel/setting/defaultSettings —
|
||||||
// powers the "Set default cert" button on the TLS form.
|
// powers the "Set default cert" button on the TLS form.
|
||||||
const defaultCert = ref('');
|
const defaultCert = ref('');
|
||||||
|
|
@ -224,13 +227,13 @@ function freshDbForm() {
|
||||||
function primeAdvancedJson() {
|
function primeAdvancedJson() {
|
||||||
if (!inbound.value) return;
|
if (!inbound.value) return;
|
||||||
try {
|
try {
|
||||||
advancedJson.value.stream = JSON.stringify(JSON.parse(inbound.value.stream.toString()), null, 2);
|
advancedStreamText.value = JSON.stringify(JSON.parse(inbound.value.stream.toString()), null, 2);
|
||||||
} catch (_e) { /* keep prior text */ }
|
} catch (_e) { /* keep prior text */ }
|
||||||
try {
|
try {
|
||||||
advancedJson.value.sniffing = JSON.stringify(JSON.parse(inbound.value.sniffing.toString()), null, 2);
|
advancedSniffingText.value = JSON.stringify(JSON.parse(inbound.value.sniffing.toString()), null, 2);
|
||||||
} catch (_e) { /* keep prior text */ }
|
} catch (_e) { /* keep prior text */ }
|
||||||
try {
|
try {
|
||||||
advancedJson.value.settings = JSON.stringify(JSON.parse(inbound.value.settings.toString()), null, 2);
|
advancedSettingsText.value = JSON.stringify(JSON.parse(inbound.value.settings.toString()), null, 2);
|
||||||
} catch (_e) { /* keep prior text */ }
|
} catch (_e) { /* keep prior text */ }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -244,6 +247,7 @@ watch(() => props.open, (next) => {
|
||||||
primeAdvancedJson();
|
primeAdvancedJson();
|
||||||
}
|
}
|
||||||
activeTabKey.value = 'basic';
|
activeTabKey.value = 'basic';
|
||||||
|
advancedSectionKey.value = 'all';
|
||||||
fetchDefaultCertSettings();
|
fetchDefaultCertSettings();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -253,18 +257,18 @@ function applyAdvancedJsonToBasic() {
|
||||||
let parsedStream;
|
let parsedStream;
|
||||||
let parsedSniffing;
|
let parsedSniffing;
|
||||||
try {
|
try {
|
||||||
parsedSettings = advancedJson.value.settings.trim()
|
parsedSettings = advancedSettingsText.value.trim()
|
||||||
? JSON.parse(advancedJson.value.settings)
|
? JSON.parse(advancedSettingsText.value)
|
||||||
: inbound.value.settings?.toJson?.();
|
: inbound.value.settings?.toJson?.();
|
||||||
} catch (e) { message.error(`Settings JSON invalid: ${e.message}`); return false; }
|
} catch (e) { message.error(`Settings JSON invalid: ${e.message}`); return false; }
|
||||||
try {
|
try {
|
||||||
parsedStream = advancedJson.value.stream.trim()
|
parsedStream = advancedStreamText.value.trim()
|
||||||
? JSON.parse(advancedJson.value.stream)
|
? JSON.parse(advancedStreamText.value)
|
||||||
: inbound.value.stream?.toJson?.();
|
: inbound.value.stream?.toJson?.();
|
||||||
} catch (e) { message.error(`Stream JSON invalid: ${e.message}`); return false; }
|
} catch (e) { message.error(`Stream JSON invalid: ${e.message}`); return false; }
|
||||||
try {
|
try {
|
||||||
parsedSniffing = advancedJson.value.sniffing.trim()
|
parsedSniffing = advancedSniffingText.value.trim()
|
||||||
? JSON.parse(advancedJson.value.sniffing)
|
? JSON.parse(advancedSniffingText.value)
|
||||||
: inbound.value.sniffing?.toJson?.();
|
: inbound.value.sniffing?.toJson?.();
|
||||||
} catch (e) { message.error(`Sniffing JSON invalid: ${e.message}`); return false; }
|
} catch (e) { message.error(`Sniffing JSON invalid: ${e.message}`); return false; }
|
||||||
|
|
||||||
|
|
@ -324,6 +328,203 @@ function onNetworkChange(next) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function parseAdvancedSliceOrFallback(rawText, fallbackValue) {
|
||||||
|
if (!rawText?.trim()) return fallbackValue;
|
||||||
|
return JSON.parse(rawText);
|
||||||
|
}
|
||||||
|
|
||||||
|
function unwrapWrappedObject(parsed, key) {
|
||||||
|
if (
|
||||||
|
parsed
|
||||||
|
&& typeof parsed === 'object'
|
||||||
|
&& !Array.isArray(parsed)
|
||||||
|
&& parsed[key] !== undefined
|
||||||
|
) {
|
||||||
|
return parsed[key];
|
||||||
|
}
|
||||||
|
return parsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
const advancedAllConfig = computed({
|
||||||
|
get: () => {
|
||||||
|
if (!inbound.value) return '';
|
||||||
|
try {
|
||||||
|
const settings = parseAdvancedSliceOrFallback(
|
||||||
|
advancedSettingsText.value,
|
||||||
|
inbound.value.settings?.toJson?.() || {},
|
||||||
|
);
|
||||||
|
const streamSettings = parseAdvancedSliceOrFallback(
|
||||||
|
advancedStreamText.value,
|
||||||
|
inbound.value.stream?.toJson?.() || {},
|
||||||
|
);
|
||||||
|
const sniffing = parseAdvancedSliceOrFallback(
|
||||||
|
advancedSniffingText.value,
|
||||||
|
inbound.value.sniffing?.toJson?.() || {},
|
||||||
|
);
|
||||||
|
return JSON.stringify({
|
||||||
|
listen: inbound.value.listen,
|
||||||
|
port: inbound.value.port,
|
||||||
|
protocol: inbound.value.protocol,
|
||||||
|
settings,
|
||||||
|
sniffing,
|
||||||
|
streamSettings,
|
||||||
|
tag: inbound.value.tag,
|
||||||
|
}, null, 2);
|
||||||
|
} catch (_e) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
set: (next) => {
|
||||||
|
let parsed;
|
||||||
|
try {
|
||||||
|
parsed = JSON.parse(next);
|
||||||
|
} catch (e) {
|
||||||
|
message.error(`All JSON invalid: ${e.message}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
||||||
|
message.error('All JSON must be an inbound object.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (typeof parsed.listen === 'string') {
|
||||||
|
inbound.value.listen = parsed.listen;
|
||||||
|
}
|
||||||
|
if (parsed.port !== undefined) {
|
||||||
|
const parsedPort = Number(parsed.port);
|
||||||
|
if (!Number.isNaN(parsedPort) && Number.isFinite(parsedPort)) {
|
||||||
|
inbound.value.port = parsedPort;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (typeof parsed.protocol === 'string' && PROTOCOLS.includes(parsed.protocol)) {
|
||||||
|
inbound.value.protocol = parsed.protocol;
|
||||||
|
}
|
||||||
|
if (typeof parsed.tag === 'string') {
|
||||||
|
inbound.value.tag = parsed.tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
const existingSettings = parseAdvancedSliceOrFallback(
|
||||||
|
advancedSettingsText.value,
|
||||||
|
inbound.value?.settings?.toJson?.() || {},
|
||||||
|
);
|
||||||
|
const settings = parsed.settings ?? existingSettings;
|
||||||
|
const streamSettings = parsed.streamSettings ?? (inbound.value?.stream?.toJson?.() || {});
|
||||||
|
const sniffing = parsed.sniffing ?? (inbound.value?.sniffing?.toJson?.() || {});
|
||||||
|
advancedSettingsText.value = JSON.stringify(settings, null, 2);
|
||||||
|
advancedStreamText.value = JSON.stringify(streamSettings, null, 2);
|
||||||
|
advancedSniffingText.value = JSON.stringify(sniffing, null, 2);
|
||||||
|
} catch (e) {
|
||||||
|
message.error(`All JSON invalid: ${e.message}`);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const advancedSettingsConfig = computed({
|
||||||
|
get: () => {
|
||||||
|
if (!inbound.value) return '';
|
||||||
|
try {
|
||||||
|
const settings = parseAdvancedSliceOrFallback(
|
||||||
|
advancedSettingsText.value,
|
||||||
|
inbound.value.settings?.toJson?.() || {},
|
||||||
|
);
|
||||||
|
return JSON.stringify({
|
||||||
|
settings,
|
||||||
|
}, null, 2);
|
||||||
|
} catch (_e) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
set: (next) => {
|
||||||
|
let parsed;
|
||||||
|
try {
|
||||||
|
parsed = JSON.parse(next);
|
||||||
|
} catch (e) {
|
||||||
|
message.error(`Settings JSON invalid: ${e.message}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const unwrapped = unwrapWrappedObject(parsed, 'settings');
|
||||||
|
if (!unwrapped || typeof unwrapped !== 'object' || Array.isArray(unwrapped)) {
|
||||||
|
message.error('Settings JSON must be an object or { settings: { ... } }.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
advancedSettingsText.value = JSON.stringify(unwrapped, null, 2);
|
||||||
|
} catch (e) {
|
||||||
|
message.error(`Settings JSON invalid: ${e.message}`);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const advancedSniffingConfig = computed({
|
||||||
|
get: () => {
|
||||||
|
if (!inbound.value) return '';
|
||||||
|
try {
|
||||||
|
const sniffing = parseAdvancedSliceOrFallback(
|
||||||
|
advancedSniffingText.value,
|
||||||
|
inbound.value.sniffing?.toJson?.() || {},
|
||||||
|
);
|
||||||
|
return JSON.stringify({ sniffing }, null, 2);
|
||||||
|
} catch (_e) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
set: (next) => {
|
||||||
|
let parsed;
|
||||||
|
try {
|
||||||
|
parsed = JSON.parse(next);
|
||||||
|
} catch (e) {
|
||||||
|
message.error(`Sniffing JSON invalid: ${e.message}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const unwrapped = unwrapWrappedObject(parsed, 'sniffing');
|
||||||
|
if (!unwrapped || typeof unwrapped !== 'object' || Array.isArray(unwrapped)) {
|
||||||
|
message.error('Sniffing JSON must be an object or { sniffing: { ... } }.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
advancedSniffingText.value = JSON.stringify(unwrapped, null, 2);
|
||||||
|
} catch (e) {
|
||||||
|
message.error(`Sniffing JSON invalid: ${e.message}`);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const advancedStreamConfig = computed({
|
||||||
|
get: () => {
|
||||||
|
if (!inbound.value) return '';
|
||||||
|
try {
|
||||||
|
const streamSettings = parseAdvancedSliceOrFallback(
|
||||||
|
advancedStreamText.value,
|
||||||
|
inbound.value.stream?.toJson?.() || {},
|
||||||
|
);
|
||||||
|
return JSON.stringify({ streamSettings }, null, 2);
|
||||||
|
} catch (_e) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
set: (next) => {
|
||||||
|
let parsed;
|
||||||
|
try {
|
||||||
|
parsed = JSON.parse(next);
|
||||||
|
} catch (e) {
|
||||||
|
message.error(`Stream JSON invalid: ${e.message}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const unwrapped = unwrapWrappedObject(parsed, 'streamSettings');
|
||||||
|
if (!unwrapped || typeof unwrapped !== 'object' || Array.isArray(unwrapped)) {
|
||||||
|
message.error('Stream JSON must be an object or { streamSettings: { ... } }.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
advancedStreamText.value = JSON.stringify(unwrapped, null, 2);
|
||||||
|
} catch (e) {
|
||||||
|
message.error(`Stream JSON invalid: ${e.message}`);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
// === Random helpers wired to the form's sync icons ==================
|
// === Random helpers wired to the form's sync icons ==================
|
||||||
function randomEmail(target) {
|
function randomEmail(target) {
|
||||||
if (target) target.email = RandomUtil.randomLowerAndNum(9);
|
if (target) target.email = RandomUtil.randomLowerAndNum(9);
|
||||||
|
|
@ -525,16 +726,16 @@ async function submit() {
|
||||||
let settings;
|
let settings;
|
||||||
try {
|
try {
|
||||||
streamSettings = canEnableStream.value
|
streamSettings = canEnableStream.value
|
||||||
? JSON.stringify(JSON.parse(advancedJson.value.stream))
|
? JSON.stringify(JSON.parse(advancedStreamText.value))
|
||||||
: (inbound.value.stream?.sockopt
|
: (inbound.value.stream?.sockopt
|
||||||
? JSON.stringify({ sockopt: inbound.value.stream.sockopt.toJson() })
|
? JSON.stringify({ sockopt: inbound.value.stream.sockopt.toJson() })
|
||||||
: '');
|
: '');
|
||||||
} catch (e) { message.error(`Stream JSON invalid: ${e.message}`); return; }
|
} catch (e) { message.error(`Stream JSON invalid: ${e.message}`); return; }
|
||||||
try {
|
try {
|
||||||
sniffing = JSON.stringify(JSON.parse(advancedJson.value.sniffing || inbound.value.sniffing.toString()));
|
sniffing = JSON.stringify(JSON.parse(advancedSniffingText.value || inbound.value.sniffing.toString()));
|
||||||
} catch (e) { message.error(`Sniffing JSON invalid: ${e.message}`); return; }
|
} catch (e) { message.error(`Sniffing JSON invalid: ${e.message}`); return; }
|
||||||
try {
|
try {
|
||||||
settings = JSON.stringify(JSON.parse(advancedJson.value.settings || inbound.value.settings.toString()));
|
settings = JSON.stringify(JSON.parse(advancedSettingsText.value || inbound.value.settings.toString()));
|
||||||
} catch (e) { message.error(`Settings JSON invalid: ${e.message}`); return; }
|
} catch (e) { message.error(`Settings JSON invalid: ${e.message}`); return; }
|
||||||
|
|
||||||
// The structured form mutates `inbound.stream` directly when the
|
// The structured form mutates `inbound.stream` directly when the
|
||||||
|
|
@ -598,7 +799,7 @@ watch(
|
||||||
() => {
|
() => {
|
||||||
if (!inbound.value?.stream) return;
|
if (!inbound.value?.stream) return;
|
||||||
try {
|
try {
|
||||||
advancedJson.value.stream = JSON.stringify(JSON.parse(inbound.value.stream.toString()), null, 2);
|
advancedStreamText.value = JSON.stringify(JSON.parse(inbound.value.stream.toString()), null, 2);
|
||||||
} catch (_e) { /* leave as is */ }
|
} catch (_e) { /* leave as is */ }
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
@ -607,7 +808,7 @@ watch(
|
||||||
() => {
|
() => {
|
||||||
if (!inbound.value?.sniffing) return;
|
if (!inbound.value?.sniffing) return;
|
||||||
try {
|
try {
|
||||||
advancedJson.value.sniffing = JSON.stringify(JSON.parse(inbound.value.sniffing.toString()), null, 2);
|
advancedSniffingText.value = JSON.stringify(JSON.parse(inbound.value.sniffing.toString()), null, 2);
|
||||||
} catch (_e) { /* leave as is */ }
|
} catch (_e) { /* leave as is */ }
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
@ -616,7 +817,7 @@ watch(
|
||||||
() => {
|
() => {
|
||||||
if (!inbound.value?.settings) return;
|
if (!inbound.value?.settings) return;
|
||||||
try {
|
try {
|
||||||
advancedJson.value.settings = JSON.stringify(JSON.parse(inbound.value.settings.toString()), null, 2);
|
advancedSettingsText.value = JSON.stringify(JSON.parse(inbound.value.settings.toString()), null, 2);
|
||||||
} catch (_e) { /* leave as is */ }
|
} catch (_e) { /* leave as is */ }
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
@ -1005,7 +1206,7 @@ watch(
|
||||||
<a-form-item>
|
<a-form-item>
|
||||||
<template #label>
|
<template #label>
|
||||||
<a-tooltip
|
<a-tooltip
|
||||||
title='Physical interface for outbound traffic. Use "auto" to detect; auto-enabled when Auto system routes is set.'>
|
title="Physical interface for outbound traffic. Use 'auto' to detect; auto-enabled when Auto system routes is set.">
|
||||||
Auto outbounds interface
|
Auto outbounds interface
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -1944,20 +2145,48 @@ watch(
|
||||||
|
|
||||||
<!-- ============================== ADVANCED ============================== -->
|
<!-- ============================== ADVANCED ============================== -->
|
||||||
<a-tab-pane key="advanced" :tab="t('pages.xray.advancedTemplate')">
|
<a-tab-pane key="advanced" :tab="t('pages.xray.advancedTemplate')">
|
||||||
<a-alert type="info" show-icon
|
<div class="advanced-shell">
|
||||||
message="Edit raw stream JSON to access advanced fields we don't yet expose through the form."
|
<div class="advanced-panel">
|
||||||
class="mb-12" />
|
<div class="advanced-panel__header">
|
||||||
<a-form layout="vertical">
|
<div>
|
||||||
<a-form-item label="settings (clients, encryption, fallbacks, …)">
|
<div class="advanced-panel__title">Inbound JSON sections</div>
|
||||||
<JsonEditor v-model:value="advancedJson.settings" min-height="280px" max-height="520px" />
|
<div class="advanced-panel__subtitle">
|
||||||
</a-form-item>
|
Full inbound JSON and focused editors for settings, sniffing, and streamSettings.
|
||||||
<a-form-item label="streamSettings">
|
</div>
|
||||||
<JsonEditor v-model:value="advancedJson.stream" min-height="280px" max-height="520px" />
|
</div>
|
||||||
</a-form-item>
|
</div>
|
||||||
<a-form-item label="sniffing (overrides the Sniffing tab when set)">
|
|
||||||
<JsonEditor v-model:value="advancedJson.sniffing" min-height="180px" max-height="360px" />
|
<a-tabs v-model:active-key="advancedSectionKey" class="advanced-inner-tabs">
|
||||||
</a-form-item>
|
<a-tab-pane key="all" tab="All">
|
||||||
</a-form>
|
<div class="advanced-editor-meta">
|
||||||
|
Full inbound object with all fields in one editor.
|
||||||
|
</div>
|
||||||
|
<JsonEditor v-model:value="advancedAllConfig" min-height="340px" max-height="560px" />
|
||||||
|
</a-tab-pane>
|
||||||
|
<a-tab-pane key="settings" tab="Settings">
|
||||||
|
<div class="advanced-editor-meta">
|
||||||
|
Xray settings block wrapper:
|
||||||
|
<code>{ settings: { ... } }</code>.
|
||||||
|
</div>
|
||||||
|
<JsonEditor v-model:value="advancedSettingsConfig" min-height="320px" max-height="540px" />
|
||||||
|
</a-tab-pane>
|
||||||
|
<a-tab-pane key="sniffingSection" tab="Sniffing">
|
||||||
|
<div class="advanced-editor-meta">
|
||||||
|
Xray sniffing block wrapper:
|
||||||
|
<code>{ sniffing: { ... } }</code>.
|
||||||
|
</div>
|
||||||
|
<JsonEditor v-model:value="advancedSniffingConfig" min-height="240px" max-height="420px" />
|
||||||
|
</a-tab-pane>
|
||||||
|
<a-tab-pane key="streamSection" tab="Stream">
|
||||||
|
<div class="advanced-editor-meta">
|
||||||
|
Xray stream block wrapper:
|
||||||
|
<code>{ streamSettings: { ... } }</code>.
|
||||||
|
</div>
|
||||||
|
<JsonEditor v-model:value="advancedStreamConfig" min-height="320px" max-height="540px" />
|
||||||
|
</a-tab-pane>
|
||||||
|
</a-tabs>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</a-tab-pane>
|
</a-tab-pane>
|
||||||
</a-tabs>
|
</a-tabs>
|
||||||
</a-modal>
|
</a-modal>
|
||||||
|
|
@ -2033,6 +2262,73 @@ watch(
|
||||||
margin-top: 4px;
|
margin-top: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.advanced-shell {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.advanced-panel {
|
||||||
|
padding: 14px;
|
||||||
|
border: 1px solid rgba(128, 128, 128, 0.18);
|
||||||
|
border-radius: 12px;
|
||||||
|
background: rgba(128, 128, 128, 0.04);
|
||||||
|
}
|
||||||
|
|
||||||
|
.advanced-panel__header {
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.advanced-panel__title {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.advanced-panel__subtitle {
|
||||||
|
margin-top: 4px;
|
||||||
|
color: rgba(0, 0, 0, 0.6);
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.advanced-inner-tabs :deep(.ant-tabs-nav) {
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.advanced-inner-tabs :deep(.ant-tabs-tab) {
|
||||||
|
padding-inline: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.advanced-editor-meta {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
color: rgba(0, 0, 0, 0.65);
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.advanced-panel {
|
||||||
|
padding: 12px;
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.advanced-inner-tabs :deep(.ant-tabs-tab) {
|
||||||
|
padding-inline: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(.dark) .advanced-panel__subtitle,
|
||||||
|
:global(.dark) .advanced-editor-meta,
|
||||||
|
:global(.ultra) .advanced-panel__subtitle,
|
||||||
|
:global(.ultra) .advanced-editor-meta {
|
||||||
|
color: rgba(255, 255, 255, 0.65);
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(.dark) .advanced-panel,
|
||||||
|
:global(.ultra) .advanced-panel {
|
||||||
|
border-color: rgba(255, 255, 255, 0.12);
|
||||||
|
background: rgba(255, 255, 255, 0.03);
|
||||||
|
}
|
||||||
|
|
||||||
.section-heading {
|
.section-heading {
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
margin: 12px 0 6px;
|
margin: 12px 0 6px;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue