style: 优化表单样式并提升表单性能

This commit is contained in:
2026-09-01 01:14:32 +08:00
parent 0901c9c99f
commit 8ceebab216
7 changed files with 737 additions and 349 deletions
+7 -42
View File
@@ -5,9 +5,7 @@
.itstudio-otp-wrap {
display: flex;
flex-direction: column;
gap: 8px;
width: 100%;
margin-top: 4px;
}
.itstudio-otp-group {
@@ -69,9 +67,9 @@
}
.itstudio-otp-send.is-countdown {
background: rgba(56, 139, 253, 0.12) !important;
border: 1px solid rgba(56, 139, 253, 0.3) !important;
color: #58a6ff !important;
background: #6b7280 !important;
border: 1px solid #7c8490 !important;
color: #e5e7eb !important;
font-variant-numeric: tabular-nums;
font-weight: 600;
}
@@ -82,28 +80,7 @@
}
.itstudio-otp-status {
display: flex;
align-items: center;
gap: 6px;
font-size: 0.84rem;
line-height: 1.45;
padding: 2px 4px;
color: var(--text-secondary);
transition: all 0.2s ease;
}
.itstudio-otp-status.is-success {
color: #3fb950;
font-weight: 500;
}
.itstudio-otp-status.is-error {
color: #f85149;
font-weight: 500;
}
.itstudio-otp-status.is-info {
color: #58a6ff;
width: 100%;
}
/* 浅色模式适配 */
@@ -118,21 +95,9 @@
}
[data-theme="light"] .itstudio-otp-send.is-countdown {
background: rgba(9, 105, 218, 0.08) !important;
border: 1px solid rgba(9, 105, 218, 0.25) !important;
color: #0969da !important;
}
[data-theme="light"] .itstudio-otp-status.is-success {
color: #1a7f37;
}
[data-theme="light"] .itstudio-otp-status.is-error {
color: #cf222e;
}
[data-theme="light"] .itstudio-otp-status.is-info {
color: #0969da;
background: #9ca3af !important;
border: 1px solid #9ca3af !important;
color: #ffffff !important;
}
@media (max-width: 480px) {
+84 -13
View File
@@ -6,6 +6,8 @@
return;
}
const OTP_COOLDOWN_SECONDS = 60;
function getLanguage() {
return document.documentElement.lang === 'en' ? 'en' : 'cn';
}
@@ -41,12 +43,18 @@
}
status.style.display = 'flex';
status.textContent = message;
status.className = 'itstudio-otp-status' + (tone ? ' is-' + tone : '');
status.className = 'itstudio-otp-status ' + (tone === 'error' ? 'frm_error_style' : 'frm_message');
}
function startCooldown(button, seconds) {
let remaining = Math.max(1, Number(seconds) || Number(config.cooldown) || 60);
let remaining = Math.max(1, Number(seconds) || OTP_COOLDOWN_SECONDS);
if (button.itstudioOtpTimer) {
window.clearInterval(button.itstudioOtpTimer);
}
button.disabled = true;
button.dataset.otpLocked = '1';
button.setAttribute('aria-disabled', 'true');
button.classList.add('is-countdown');
const update = function () {
@@ -55,6 +63,8 @@
if (remaining < 0) {
window.clearInterval(button.itstudioOtpTimer);
button.itstudioOtpTimer = null;
button.dataset.otpLocked = '0';
button.setAttribute('aria-disabled', 'false');
button.classList.remove('is-countdown');
button.textContent = config.labels.send || '发送验证码';
button.disabled = false;
@@ -65,7 +75,36 @@
button.itstudioOtpTimer = window.setInterval(update, 1000);
}
async function readAjaxResult(response) {
const raw = await response.text();
const normalized = raw.replace(/^\uFEFF/, '').trim();
if (!normalized) {
throw new Error('Empty AJAX response');
}
const result = JSON.parse(normalized);
if (result && typeof result === 'object' && typeof result.success !== 'undefined') {
return {
success: result.success === true || result.success === 1 || result.success === '1',
payload: result.data && typeof result.data === 'object' ? result.data : {}
};
}
if (result && typeof result === 'object' && (result.message_cn || result.message_en)) {
return {
success: true,
payload: result
};
}
throw new Error('Unexpected AJAX response');
}
async function sendCode(form, button, status) {
if (button.dataset.otpLocked === '1' || button.disabled) {
return;
}
const emailInput = findField(form, config.emailFieldId);
const email = emailInput ? emailInput.value.trim() : '';
if (!email) {
@@ -79,7 +118,10 @@
return;
}
// Block rapid duplicate clicks while the request is in flight.
button.disabled = true;
button.dataset.otpLocked = '1';
button.setAttribute('aria-disabled', 'true');
button.classList.add('is-loading');
button.textContent = config.labels.sending || '发送中…';
setStatus(status, config.labels.sending || '正在发送验证码…', 'info');
@@ -95,26 +137,26 @@
nonce: config.nonce
}).toString()
});
const result = await response.json();
const payload = result && result.data ? result.data : {};
const result = await readAjaxResult(response);
const payload = result.payload || {};
button.classList.remove('is-loading');
if (!result.success) {
setStatus(status, getMessage(payload, config.labels.networkError || '发送失败,请稍后重试。'), 'error');
if (payload.wait) {
startCooldown(button, payload.wait);
} else {
button.textContent = config.labels.send || '发送验证码';
button.disabled = false;
}
button.dataset.otpLocked = '0';
button.setAttribute('aria-disabled', 'false');
button.textContent = config.labels.send || '发送验证码';
button.disabled = false;
return;
}
setStatus(status, getMessage(payload, '验证码已发送,请检查邮箱及垃圾箱。'), 'success');
startCooldown(button, payload.cooldown || config.cooldown);
startCooldown(button, payload.cooldown || OTP_COOLDOWN_SECONDS);
} catch (error) {
button.classList.remove('is-loading');
setStatus(status, config.labels.networkError || '网络错误,请稍后重试。', 'error');
button.dataset.otpLocked = '0';
button.setAttribute('aria-disabled', 'false');
button.textContent = config.labels.send || '发送验证码';
button.disabled = false;
}
@@ -150,6 +192,8 @@
button.type = 'button';
button.className = 'itstudio-otp-send';
button.textContent = config.labels.send || '发送验证码';
button.dataset.otpLocked = '0';
button.setAttribute('aria-disabled', 'false');
const status = document.createElement('div');
status.className = 'itstudio-otp-status';
@@ -171,7 +215,34 @@
});
}
let mountQueued = false;
const scheduleMount = function () {
if (mountQueued) {
return;
}
mountQueued = true;
window.requestAnimationFrame(function () {
mountQueued = false;
mount();
});
};
mount();
const observer = new MutationObserver(mount);
observer.observe(document.body, {childList: true, subtree: true});
const observerRoot = document.querySelector('.join-form-content') || document.body;
const observer = new MutationObserver(function (mutations) {
const formStructureChanged = mutations.some(function (mutation) {
return Array.from(mutation.addedNodes).concat(Array.from(mutation.removedNodes)).some(function (node) {
return node.nodeType === 1 && (
node.matches('.frm_forms, form') ||
Boolean(node.querySelector && node.querySelector('.frm_forms, form'))
);
});
});
if (formStructureChanged) {
scheduleMount();
}
});
observer.observe(observerRoot, {childList: true, subtree: true});
})();
@@ -57,6 +57,36 @@ function itstudio_join_otp_random_code() {
return (string) wp_rand(100000, 999999);
}
function itstudio_join_otp_email_exists_in_form($form_id, $field_id, $email) {
global $wpdb;
$form_id = absint($form_id);
$field_id = absint($field_id);
$email = itstudio_join_otp_normalize_email($email);
if ($form_id <= 0 || $field_id <= 0 || $email === '') {
return false;
}
$items_table = $wpdb->prefix . 'frm_items';
$metas_table = $wpdb->prefix . 'frm_item_metas';
$count = $wpdb->get_var(
$wpdb->prepare(
"SELECT COUNT(1)
FROM {$metas_table} AS meta
INNER JOIN {$items_table} AS item ON item.id = meta.item_id
WHERE item.form_id = %d
AND item.is_draft = 0
AND meta.field_id = %d
AND LOWER(TRIM(meta.meta_value)) = %s",
$form_id,
$field_id,
$email
)
);
return (int) $count > 0;
}
function itstudio_join_otp_json_error($message_cn, $message_en, $status = 400, $extra = array()) {
wp_send_json_error(
array_merge(
@@ -85,6 +115,10 @@ function itstudio_join_otp_send_ajax() {
itstudio_join_otp_json_error('请输入有效的邮箱地址。', 'Please enter a valid email address.', 400);
}
if (itstudio_join_otp_email_exists_in_form($config['form_id'], $config['email_field_id'], $email)) {
itstudio_join_otp_json_error('该邮箱已经报名,无需重复提交。', 'This email has already been used to apply.', 409);
}
$ip = itstudio_join_otp_get_client_ip();
$otp_key = itstudio_join_otp_key($email, $config['form_id']);
$existing = get_transient($otp_key);
+490 -277
View File
@@ -1,4 +1,4 @@
.join-page {
.join-page {
padding: 36px 0 72px;
}
@@ -659,32 +659,30 @@
overflow-wrap: anywhere;
}
/* =========================================
招新报名表单与 Formidable Forms 样式全面重构
========================================= */
.join-form-card {
position: relative;
overflow: hidden;
border: 1px solid color-mix(in srgb, var(--color-primary) 28%, var(--border-default) 72%);
border-radius: 6px;
border: 1px solid color-mix(in srgb, var(--color-primary) 32%, var(--border-default) 68%);
border-radius: 12px;
background:
linear-gradient(
118deg,
color-mix(in srgb, var(--color-primary) 12%, transparent) 0%,
transparent 36%
),
radial-gradient(
120% 80% at 100% 0%,
color-mix(in srgb, var(--color-primary) 14%, transparent) 0%,
transparent 52%
120% 90% at 100% 0%,
color-mix(in srgb, var(--color-primary) 12%, transparent) 0%,
transparent 55%
),
linear-gradient(
180deg,
color-mix(in srgb, var(--bg-card) 84%, #0f1a2b 16%) 0%,
color-mix(in srgb, var(--bg-card) 95%, transparent) 100%
color-mix(in srgb, var(--bg-card) 92%, #0d1117 8%) 0%,
color-mix(in srgb, var(--bg-card) 98%, transparent) 100%
);
padding: 18px;
padding: 24px;
box-shadow:
0 22px 40px -32px color-mix(in srgb, #000000 78%, transparent),
inset 0 1px 0 color-mix(in srgb, #9bc9ff 18%, transparent),
inset 0 -1px 0 color-mix(in srgb, #0a101a 70%, transparent);
0 16px 36px -20px color-mix(in srgb, #000000 70%, transparent),
inset 0 1px 0 color-mix(in srgb, #9bc9ff 16%, transparent);
}
.join-form-card::before {
@@ -695,32 +693,32 @@
background:
repeating-linear-gradient(
0deg,
color-mix(in srgb, var(--color-primary) 8%, transparent) 0 1px,
transparent 1px 13px
color-mix(in srgb, var(--color-primary) 6%, transparent) 0 1px,
transparent 1px 16px
),
repeating-linear-gradient(
90deg,
color-mix(in srgb, var(--color-primary) 7%, transparent) 0 1px,
transparent 1px 18px
color-mix(in srgb, var(--color-primary) 5%, transparent) 0 1px,
transparent 1px 20px
);
opacity: 0.26;
opacity: 0.22;
}
.join-form-card::after {
content: "";
position: absolute;
inset: 10px;
inset: 12px;
pointer-events: none;
background:
linear-gradient(90deg, color-mix(in srgb, var(--color-primary) 72%, transparent), transparent)
top left / 88px 1px no-repeat,
linear-gradient(180deg, color-mix(in srgb, var(--color-primary) 72%, transparent), transparent)
top left / 1px 44px no-repeat,
linear-gradient(270deg, color-mix(in srgb, var(--color-primary) 48%, transparent), transparent)
bottom right / 66px 1px no-repeat,
linear-gradient(0deg, color-mix(in srgb, var(--color-primary) 48%, transparent), transparent)
linear-gradient(90deg, color-mix(in srgb, var(--color-primary) 70%, transparent), transparent)
top left / 80px 1px no-repeat,
linear-gradient(180deg, color-mix(in srgb, var(--color-primary) 70%, transparent), transparent)
top left / 1px 40px no-repeat,
linear-gradient(270deg, color-mix(in srgb, var(--color-primary) 50%, transparent), transparent)
bottom right / 60px 1px no-repeat,
linear-gradient(0deg, color-mix(in srgb, var(--color-primary) 50%, transparent), transparent)
bottom right / 1px 30px no-repeat;
opacity: 0.65;
opacity: 0.6;
}
.join-form-card > * {
@@ -729,7 +727,7 @@
}
.join-form-card + .join-panel-title {
margin-top: 16px;
margin-top: 20px;
}
.join-form-card-placeholder {
@@ -739,13 +737,14 @@
}
.join-form-content {
margin-top: 14px;
margin-top: 10px;
}
.join-form-content form {
margin: 0;
}
/* --- 录取进度查询表单 --- */
.join-progress-query-form {
display: grid;
gap: 12px;
@@ -775,7 +774,7 @@
border-radius: 8px;
background: color-mix(in srgb, var(--bg-card) 90%, transparent) !important;
color: var(--text-primary) !important;
padding: 9px 10px;
padding: 10px 12px;
line-height: 1.3;
transition: border-color var(--duration-fast), box-shadow var(--duration-fast), background-color var(--duration-fast);
}
@@ -791,10 +790,10 @@
.join-progress-query-field input:focus {
outline: none;
border-color: color-mix(in srgb, var(--color-primary) 55%, var(--border-default) 45%) !important;
background: color-mix(in srgb, var(--bg-card) 90%, transparent) !important;
border-color: var(--color-primary) !important;
background: color-mix(in srgb, var(--bg-card) 95%, transparent) !important;
color: var(--text-primary) !important;
box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-primary) 16%, transparent) !important;
box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-primary) 22%, transparent) !important;
}
.join-progress-query-field input:-webkit-autofill,
@@ -827,23 +826,25 @@
.join-progress-query-submit {
border: 1px solid color-mix(in srgb, var(--color-primary) 48%, var(--border-default) 52%);
border-radius: 10px;
border-radius: 8px;
background: color-mix(in srgb, var(--color-primary) 18%, var(--bg-card) 82%);
color: var(--text-primary);
padding: 9px 16px;
padding: 10px 18px;
font-size: 0.9rem;
font-weight: 600;
cursor: pointer;
transition: all 0.2s ease;
}
.join-progress-query-submit:hover {
background: color-mix(in srgb, var(--color-primary) 24%, var(--bg-card) 76%);
background: color-mix(in srgb, var(--color-primary) 28%, var(--bg-card) 72%);
transform: translateY(-1px);
}
.join-progress-query-feedback {
margin: 2px 0 0;
padding: 10px 12px;
border-radius: 10px;
margin: 8px 0 0;
padding: 10px 14px;
border-radius: 8px;
border: 1px solid color-mix(in srgb, var(--border-default) 80%, transparent);
background: color-mix(in srgb, var(--bg-card) 90%, transparent);
color: var(--text-primary);
@@ -871,296 +872,390 @@
background: color-mix(in srgb, #c34646 14%, var(--bg-card) 86%);
}
.join-form-content .frm_forms {
/* --- Formidable 表单字段容器与排版 --- */
.join-form-content .frm_forms,
.join-form-content .frm_form_fields {
margin: 0;
}
.join-form-content .frm_style_formidable-style.with_frm_style .frm_form_fields,
.join-form-content .frm_style_formidable-style.with_frm_style .frm_submit {
max-width: none;
}
.join-form-content .frm_style_formidable-style.with_frm_style,
.join-form-content .frm_style_formidable-style.with_frm_style .frm_form_fields,
.join-form-content .frm_style_formidable-style.with_frm_style .frm_form_field,
.join-form-content .frm_style_formidable-style.with_frm_style .frm_field_wrapper {
color: color-mix(in srgb, var(--text-primary) 95%, #ffffff 5%) !important;
.join-form-content .frm_fields_container {
display: flex;
flex-direction: column;
gap: 16px;
}
.join-form-content .frm_style_formidable-style.with_frm_style .frm_form_field {
margin-bottom: 14px !important;
.join-form-content .frm_form_field,
.join-form-content .form-field {
margin-bottom: 0 !important;
display: flex;
flex-direction: column;
}
.join-form-content .frm_style_formidable-style.with_frm_style label {
color: color-mix(in srgb, var(--text-primary) 95%, #ffffff 5%) !important;
opacity: 1 !important;
}
.join-form-content .frm_style_formidable-style.with_frm_style .frm_primary_label,
.join-form-content .frm_style_formidable-style.with_frm_style .frm_section_heading h3,
.join-form-content .frm_style_formidable-style.with_frm_style .frm_inline_box label,
.join-form-content .frm_style_formidable-style.with_frm_style .frm_radio label,
.join-form-content .frm_style_formidable-style.with_frm_style .frm_checkbox label,
.join-form-content .frm_style_formidable-style.with_frm_style .frm_opt_container label {
color: color-mix(in srgb, var(--text-primary) 92%, #ffffff 8%) !important;
.join-form-content .frm_primary_label,
.join-form-content label.frm_primary_label,
.join-form-content .frm_section_heading h3,
.join-form-content .frm_inline_box label {
color: var(--text-primary) !important;
font-size: 0.92rem !important;
font-weight: 600 !important;
line-height: 1.4 !important;
letter-spacing: 0.01em !important;
margin-bottom: 7px !important;
display: inline-flex !important;
align-items: center !important;
gap: 3px !important;
opacity: 1 !important;
letter-spacing: 0.01em;
}
.join-form-content .frm_style_formidable-style.with_frm_style .frm_required {
color: #ff6767 !important;
.join-form-content .frm_required {
color: #f85149 !important;
font-weight: 700 !important;
font-size: 1em !important;
margin-left: 2px !important;
}
.join-form-content .frm_style_formidable-style.with_frm_style .frm_description,
.join-form-content .frm_style_formidable-style.with_frm_style .frm_error,
.join-form-content .frm_style_formidable-style.with_frm_style .frm_error_style {
color: color-mix(in srgb, var(--text-primary) 82%, var(--text-secondary) 18%) !important;
}
.join-form-content .frm_style_formidable-style.with_frm_style .frm_error_style,
.join-form-content .frm_style_formidable-style.with_frm_style .frm_error {
border-left: 3px solid #ff6767 !important;
background: color-mix(in srgb, #ff6767 10%, transparent) !important;
padding: 8px 10px !important;
border-radius: 4px;
}
.join-form-content .frm_style_formidable-style.with_frm_style .frm_message,
.join-form-content .frm_style_formidable-style.with_frm_style .frm_success_style,
.join-form-content .frm_style_formidable-style.with_frm_style .frm_success {
border-left: 3px solid #42b983 !important;
background: color-mix(in srgb, #42b983 14%, transparent) !important;
color: color-mix(in srgb, var(--text-primary) 94%, #ffffff 6%) !important;
border-radius: 4px;
padding: 10px 12px !important;
}
.join-form-content .frm_style_formidable-style.with_frm_style input[type="text"],
.join-form-content .frm_style_formidable-style.with_frm_style input[type="email"],
.join-form-content .frm_style_formidable-style.with_frm_style input[type="number"],
.join-form-content .frm_style_formidable-style.with_frm_style input[type="tel"],
.join-form-content .frm_style_formidable-style.with_frm_style input[type="date"],
.join-form-content .frm_style_formidable-style.with_frm_style input[type="datetime-local"],
.join-form-content .frm_style_formidable-style.with_frm_style textarea,
.join-form-content .frm_style_formidable-style.with_frm_style select {
background: color-mix(in srgb, var(--bg-body) 84%, #ffffff 16%) !important;
border: 1px solid color-mix(in srgb, var(--border-default) 42%, var(--color-primary) 58%) !important;
color: color-mix(in srgb, var(--text-primary) 96%, #ffffff 4%) !important;
min-height: 42px;
/* --- 顶部全局错误/提示横幅 (Modern Alert Banner) --- */
.join-form-content .frm_error_style,
.join-form-content .frm_message.frm_error_style,
.join-form-content div.frm_error_style,
.join-form-content .frm_error {
position: relative !important;
display: flex !important;
align-items: center !important;
gap: 10px !important;
padding: 12px 16px 12px 42px !important;
border-radius: 8px !important;
padding: 10px 12px !important;
border: 1px solid rgba(248, 81, 73, 0.4) !important;
border-left: 4px solid #f85149 !important;
background: linear-gradient(135deg, rgba(248, 81, 73, 0.16) 0%, rgba(248, 81, 73, 0.06) 100%) !important;
color: #ff7b72 !important;
font-size: 0.9rem !important;
font-weight: 500 !important;
line-height: 1.45 !important;
margin: 8px 0 18px 0 !important;
box-shadow: 0 4px 12px rgba(248, 81, 73, 0.1) !important;
}
.join-form-content .frm_style_formidable-style.with_frm_style input::placeholder,
.join-form-content .frm_style_formidable-style.with_frm_style textarea::placeholder {
color: color-mix(in srgb, var(--text-secondary) 78%, var(--text-primary) 22%) !important;
opacity: 1;
.join-form-content .frm_error_style::before,
.join-form-content .frm_message.frm_error_style::before,
.join-form-content .frm_error::before {
content: "" !important;
position: absolute !important;
left: 14px !important;
top: 50% !important;
transform: translateY(-50%) !important;
width: 18px !important;
height: 18px !important;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23f85149' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cline x1='12' y1='8' x2='12' y2='12'%3E%3C/line%3E%3Cline x1='12' y1='16' x2='12.01' y2='16'%3E%3C/line%3E%3C/svg%3E") !important;
background-repeat: no-repeat !important;
background-size: contain !important;
}
.join-form-content .frm_style_formidable-style.with_frm_style input[type="text"]:focus,
.join-form-content .frm_style_formidable-style.with_frm_style input[type="email"]:focus,
.join-form-content .frm_style_formidable-style.with_frm_style input[type="number"]:focus,
.join-form-content .frm_style_formidable-style.with_frm_style input[type="tel"]:focus,
.join-form-content .frm_style_formidable-style.with_frm_style input[type="date"]:focus,
.join-form-content .frm_style_formidable-style.with_frm_style input[type="datetime-local"]:focus,
.join-form-content .frm_style_formidable-style.with_frm_style textarea:focus,
.join-form-content .frm_style_formidable-style.with_frm_style select:focus {
border-color: color-mix(in srgb, var(--color-primary) 76%, #8ec9ff 24%) !important;
box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-primary) 24%, transparent) !important;
/* --- 成功提示 (Success Message) --- */
.join-form-content .frm_message,
.join-form-content .frm_success_style,
.join-form-content .frm_success {
position: relative !important;
display: flex !important;
align-items: center !important;
gap: 10px !important;
padding: 12px 16px 12px 42px !important;
border-radius: 8px !important;
border: 1px solid rgba(63, 185, 80, 0.4) !important;
border-left: 4px solid #3fb950 !important;
background: linear-gradient(135deg, rgba(63, 185, 80, 0.16) 0%, rgba(63, 185, 80, 0.06) 100%) !important;
color: #7ee787 !important;
font-size: 0.9rem !important;
font-weight: 500 !important;
line-height: 1.45 !important;
margin-bottom: 18px !important;
}
.join-form-content .frm_message::before,
.join-form-content .frm_success_style::before,
.join-form-content .frm_success::before {
content: "" !important;
position: absolute !important;
left: 14px !important;
top: 50% !important;
transform: translateY(-50%) !important;
width: 18px !important;
height: 18px !important;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%233fb950' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M22 11.08V12a10 10 0 1 1-5.93-9.14'%3E%3C/path%3E%3Cpolyline points='22 4 12 14.01 9 11.01'%3E%3C/polyline%3E%3C/svg%3E") !important;
background-repeat: no-repeat !important;
background-size: contain !important;
}
.join-form-content .frm_description {
color: var(--text-secondary) !important;
font-size: 0.82rem !important;
line-height: 1.45 !important;
margin-top: 4px !important;
}
/* --- 输入框统一质感 (Text, Email, Tel, Number, Select, Textarea) --- */
.join-form-content input[type="text"],
.join-form-content input[type="email"],
.join-form-content input[type="number"],
.join-form-content input[type="tel"],
.join-form-content input[type="password"],
.join-form-content input[type="date"],
.join-form-content input[type="datetime-local"],
.join-form-content textarea,
.join-form-content select {
display: block !important;
width: 100% !important;
min-height: 44px !important;
padding: 10px 14px !important;
font-size: 0.94rem !important;
line-height: 1.4 !important;
font-family: inherit !important;
color: #f0f6fc !important;
background: rgba(13, 17, 23, 0.72) !important;
border: 1px solid rgba(240, 246, 252, 0.14) !important;
border-radius: 8px !important;
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.25) !important;
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1) !important;
box-sizing: border-box !important;
}
.join-form-content input[type="text"]:hover,
.join-form-content input[type="email"]:hover,
.join-form-content input[type="number"]:hover,
.join-form-content input[type="tel"]:hover,
.join-form-content input[type="password"]:hover,
.join-form-content input[type="date"]:hover,
.join-form-content input[type="datetime-local"]:hover,
.join-form-content textarea:hover,
.join-form-content select:hover {
border-color: rgba(88, 166, 255, 0.45) !important;
background: rgba(22, 27, 34, 0.85) !important;
}
.join-form-content input[type="text"]:focus,
.join-form-content input[type="email"]:focus,
.join-form-content input[type="number"]:focus,
.join-form-content input[type="tel"]:focus,
.join-form-content input[type="password"]:focus,
.join-form-content input[type="date"]:focus,
.join-form-content input[type="datetime-local"]:focus,
.join-form-content textarea:focus,
.join-form-content select:focus {
border-color: #58a6ff !important;
background: rgba(22, 27, 34, 0.95) !important;
color: #ffffff !important;
box-shadow: 0 0 0 3px rgba(56, 139, 253, 0.28), inset 0 1px 2px rgba(0, 0, 0, 0.2) !important;
outline: none !important;
}
.join-form-content .frm_style_formidable-style.with_frm_style .iti {
.join-form-content input::placeholder,
.join-form-content textarea::placeholder {
color: #6d737c !important;
opacity: 1 !important;
}
.join-form-content textarea {
min-height: 96px !important;
resize: vertical;
}
/* --- 自动填充处理 --- */
.join-form-content input:-webkit-autofill,
.join-form-content input:-webkit-autofill:hover,
.join-form-content input:-webkit-autofill:focus,
.join-form-content textarea:-webkit-autofill,
.join-form-content textarea:-webkit-autofill:hover,
.join-form-content textarea:-webkit-autofill:focus,
.join-form-content select:-webkit-autofill,
.join-form-content select:-webkit-autofill:hover,
.join-form-content select:-webkit-autofill:focus {
-webkit-text-fill-color: #f0f6fc !important;
-webkit-box-shadow: 0 0 0 1000px #161b22 inset !important;
box-shadow: 0 0 0 1000px #161b22 inset !important;
caret-color: #f0f6fc !important;
transition: background-color 9999s ease-out 0s !important;
}
/* --- 国际电话组件 (iti) --- */
.join-form-content .iti {
width: 100% !important;
}
.join-form-content .frm_style_formidable-style.with_frm_style .iti input[type="tel"] {
.join-form-content .iti input[type="tel"] {
padding-right: 12px !important;
padding-left: calc(var(--iti-selected-country-arrow-padding, 64px) + 4px) !important;
}
.join-form-content .frm_style_formidable-style.with_frm_style .iti__selected-country {
.join-form-content .iti__selected-country {
border-top-left-radius: 8px;
border-bottom-left-radius: 8px;
}
.join-form-content .frm_style_formidable-style.with_frm_style input:-webkit-autofill,
.join-form-content .frm_style_formidable-style.with_frm_style input:-webkit-autofill:hover,
.join-form-content .frm_style_formidable-style.with_frm_style input:-webkit-autofill:focus,
.join-form-content .frm_style_formidable-style.with_frm_style textarea:-webkit-autofill,
.join-form-content .frm_style_formidable-style.with_frm_style textarea:-webkit-autofill:hover,
.join-form-content .frm_style_formidable-style.with_frm_style textarea:-webkit-autofill:focus,
.join-form-content .frm_style_formidable-style.with_frm_style select:-webkit-autofill,
.join-form-content .frm_style_formidable-style.with_frm_style select:-webkit-autofill:hover,
.join-form-content .frm_style_formidable-style.with_frm_style select:-webkit-autofill:focus {
-webkit-text-fill-color: color-mix(in srgb, var(--text-primary) 96%, #ffffff 4%) !important;
-webkit-box-shadow: 0 0 0 1000px color-mix(in srgb, var(--bg-body) 84%, #ffffff 16%) inset !important;
box-shadow: 0 0 0 1000px color-mix(in srgb, var(--bg-body) 84%, #ffffff 16%) inset !important;
caret-color: color-mix(in srgb, var(--text-primary) 96%, #ffffff 4%) !important;
transition: background-color 9999s ease-out 0s !important;
}
.join-form-content .frm_style_formidable-style.with_frm_style .iti__dropdown-content {
background: color-mix(in srgb, var(--bg-card) 94%, var(--bg-body) 6%) !important;
border: 1px solid color-mix(in srgb, var(--border-default) 46%, var(--color-primary) 54%) !important;
color: color-mix(in srgb, var(--text-primary) 92%, #ffffff 8%) !important;
box-shadow: 0 18px 36px -22px color-mix(in srgb, #000000 68%, transparent);
}
.join-form-content .frm_style_formidable-style.with_frm_style .iti__search-input-wrapper {
margin: 6px 8px !important;
}
.join-form-content .frm_style_formidable-style.with_frm_style .iti__search-input {
border: 1px solid color-mix(in srgb, var(--border-default) 38%, var(--color-primary) 62%) !important;
background: color-mix(in srgb, var(--bg-body) 84%, #ffffff 16%) !important;
color: color-mix(in srgb, var(--text-primary) 94%, #ffffff 6%) !important;
min-height: 40px !important;
}
.join-form-content .frm_style_formidable-style.with_frm_style .iti__search-input::placeholder {
color: color-mix(in srgb, var(--text-secondary) 76%, var(--text-primary) 24%) !important;
opacity: 1;
}
.join-form-content .frm_style_formidable-style.with_frm_style .iti__country-list {
background: transparent !important;
}
.join-form-content .frm_style_formidable-style.with_frm_style .iti__country {
color: color-mix(in srgb, var(--text-primary) 90%, #ffffff 10%) !important;
}
.join-form-content .frm_style_formidable-style.with_frm_style .iti__dial-code,
.join-form-content .frm_style_formidable-style.with_frm_style .iti__country-name {
color: color-mix(in srgb, var(--text-primary) 88%, var(--text-secondary) 12%) !important;
}
.join-form-content .frm_style_formidable-style.with_frm_style .iti__country.iti__highlight,
.join-form-content .frm_style_formidable-style.with_frm_style .iti__country:hover {
background: color-mix(in srgb, var(--color-primary) 16%, var(--bg-card) 84%) !important;
}
.join-form-content .frm_style_formidable-style.with_frm_style .iti__divider {
border-bottom-color: color-mix(in srgb, var(--border-default) 70%, transparent) !important;
}
.join-form-content .iti__dropdown-content,
.frm_forms.with_frm_style .iti__dropdown-content {
background: color-mix(in srgb, var(--bg-card) 94%, var(--bg-body) 6%) !important;
border: 1px solid color-mix(in srgb, var(--border-default) 46%, var(--color-primary) 54%) !important;
color: color-mix(in srgb, var(--text-primary) 92%, #ffffff 8%) !important;
box-shadow: 0 18px 36px -22px color-mix(in srgb, #000000 68%, transparent);
}
.frm_forms.with_frm_style .iti__search-input-wrapper {
margin: 6px 8px !important;
background: #161b22 !important;
border: 1px solid rgba(56, 139, 253, 0.4) !important;
color: #f0f6fc !important;
box-shadow: 0 18px 36px -16px rgba(0, 0, 0, 0.75);
border-radius: 8px;
}
.join-form-content .iti__search-input,
.frm_forms.with_frm_style .iti__search-input {
border: 1px solid color-mix(in srgb, var(--border-default) 38%, var(--color-primary) 62%) !important;
background: color-mix(in srgb, var(--bg-body) 84%, #ffffff 16%) !important;
color: color-mix(in srgb, var(--text-primary) 94%, #ffffff 6%) !important;
min-height: 40px !important;
}
.frm_forms.with_frm_style .iti__search-input::placeholder {
color: color-mix(in srgb, var(--text-secondary) 76%, var(--text-primary) 24%) !important;
opacity: 1;
}
.frm_forms.with_frm_style .iti__country-list {
background: transparent !important;
border: 1px solid rgba(240, 246, 252, 0.2) !important;
background: #0d1117 !important;
color: #f0f6fc !important;
min-height: 38px !important;
border-radius: 6px;
}
.join-form-content .iti__country,
.frm_forms.with_frm_style .iti__country {
color: color-mix(in srgb, var(--text-primary) 90%, #ffffff 10%) !important;
}
.frm_forms.with_frm_style .iti__dial-code,
.frm_forms.with_frm_style .iti__country-name {
color: color-mix(in srgb, var(--text-primary) 88%, var(--text-secondary) 12%) !important;
color: #c9d1d9 !important;
}
.join-form-content .iti__country.iti__highlight,
.join-form-content .iti__country:hover,
.frm_forms.with_frm_style .iti__country.iti__highlight,
.frm_forms.with_frm_style .iti__country:hover {
background: color-mix(in srgb, var(--color-primary) 16%, var(--bg-card) 84%) !important;
background: rgba(56, 139, 253, 0.2) !important;
color: #ffffff !important;
}
.join-form-content .iti__divider,
.frm_forms.with_frm_style .iti__divider {
border-bottom-color: color-mix(in srgb, var(--border-default) 70%, transparent) !important;
border-bottom-color: rgba(240, 246, 252, 0.1) !important;
}
.join-form-content .frm_style_formidable-style.with_frm_style input[type="checkbox"],
.join-form-content .frm_style_formidable-style.with_frm_style input[type="radio"] {
accent-color: var(--color-primary);
transform: scale(1.06);
}
.join-form-content .frm_style_formidable-style.with_frm_style .frm_checkbox label,
.join-form-content .frm_style_formidable-style.with_frm_style .frm_radio label,
.join-form-content .frm_style_formidable-style.with_frm_style .frm_opt_container label {
line-height: 1.55 !important;
font-size: 0.96rem !important;
}
.join-form-content .frm_style_formidable-style.with_frm_style .frm_submit {
/* --- 选项卡片化重构 (Checkbox & Radio Chips) --- */
.join-form-content .frm_opt_container {
display: flex !important;
flex-wrap: wrap;
gap: 10px;
align-items: center;
flex-wrap: wrap !important;
gap: 8px 12px !important;
margin-top: 6px !important;
}
.join-form-content .frm_style_formidable-style.with_frm_style input[type="submit"],
.join-form-content .frm_style_formidable-style.with_frm_style button.frm_button_submit {
border-radius: 10px;
border: 1px solid color-mix(in srgb, var(--color-primary) 82%, #9cd3ff 18%) !important;
background: linear-gradient(
180deg,
color-mix(in srgb, var(--color-primary) 82%, #78c3ff 18%) 0%,
color-mix(in srgb, var(--color-primary) 92%, #5ea7f8 8%) 100%
) !important;
.join-form-content .frm_checkbox,
.join-form-content .frm_radio {
margin: 0 !important;
display: inline-flex !important;
align-items: center !important;
}
.join-form-content .frm_checkbox label,
.join-form-content .frm_radio label {
display: inline-flex !important;
align-items: center !important;
gap: 8px !important;
padding: 8px 14px !important;
border-radius: 8px !important;
border: 1px solid rgba(240, 246, 252, 0.12) !important;
background: rgba(22, 27, 34, 0.6) !important;
color: var(--text-primary) !important;
font-size: 0.92rem !important;
font-weight: 500 !important;
line-height: 1.4 !important;
cursor: pointer !important;
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1) !important;
user-select: none !important;
}
.join-form-content .frm_checkbox label:hover,
.join-form-content .frm_radio label:hover {
border-color: rgba(88, 166, 255, 0.45) !important;
background: rgba(56, 139, 253, 0.1) !important;
transform: translateY(-1px);
}
.join-form-content .frm_checkbox input[type="checkbox"],
.join-form-content .frm_radio input[type="radio"] {
width: 16px !important;
min-height: auto !important;
height: 16px !important;
margin: 0 !important;
padding: 0 !important;
accent-color: var(--color-primary) !important;
cursor: pointer !important;
}
/* --- 提交与操作按钮 (Submit & Actions) --- */
.join-form-content .frm_submit {
display: flex !important;
flex-wrap: wrap !important;
gap: 12px !important;
align-items: center !important;
margin-top: 24px !important;
padding-top: 14px !important;
border-top: 1px solid rgba(240, 246, 252, 0.08) !important;
max-width: none !important;
}
.join-form-content input[type="submit"],
.join-form-content button.frm_button_submit {
min-height: 46px !important;
padding: 0 28px !important;
border-radius: 8px !important;
border: 1px solid rgba(255, 255, 255, 0.16) !important;
background: linear-gradient(135deg, #1f6feb 0%, #1158c7 100%) !important;
color: #ffffff !important;
font-weight: 700 !important;
letter-spacing: 0.01em;
min-height: 44px;
padding: 0 20px !important;
box-shadow: 0 8px 18px -12px color-mix(in srgb, var(--color-primary) 65%, transparent);
font-size: 0.95rem !important;
font-weight: 600 !important;
letter-spacing: 0.02em !important;
cursor: pointer !important;
box-shadow: 0 3px 12px rgba(31, 111, 235, 0.35) !important;
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1) !important;
user-select: none !important;
}
.join-form-content .frm_style_formidable-style.with_frm_style input[type="submit"]:hover,
.join-form-content .frm_style_formidable-style.with_frm_style button.frm_button_submit:hover {
filter: brightness(1.05);
.join-form-content input[type="submit"]:hover,
.join-form-content button.frm_button_submit:hover {
transform: translateY(-1px) !important;
filter: brightness(1.08) !important;
box-shadow: 0 6px 18px rgba(31, 111, 235, 0.45) !important;
}
.join-form-content .frm_style_formidable-style.with_frm_style .frm_save_draft,
.join-form-content .frm_style_formidable-style.with_frm_style button[name*="draft"],
.join-form-content .frm_style_formidable-style.with_frm_style input[name*="draft"],
.join-form-content .frm_style_formidable-style.with_frm_style button[value*="草稿"],
.join-form-content .frm_style_formidable-style.with_frm_style input[value*="草稿"],
.join-form-content .frm_style_formidable-style.with_frm_style button[value*="Draft"],
.join-form-content .frm_style_formidable-style.with_frm_style input[value*="Draft"] {
border: 1px solid color-mix(in srgb, var(--border-default) 30%, var(--color-primary) 70%) !important;
background: color-mix(in srgb, var(--bg-card) 88%, transparent) !important;
color: var(--color-primary) !important;
.join-form-content input[type="submit"]:active,
.join-form-content button.frm_button_submit:active {
transform: translateY(0) !important;
filter: brightness(0.96) !important;
}
.join-form-content .frm_save_draft,
.join-form-content button[name*="draft"],
.join-form-content input[name*="draft"],
.join-form-content button[value*="草稿"],
.join-form-content input[value*="草稿"],
.join-form-content button[value*="Draft"],
.join-form-content input[value*="Draft"] {
min-height: 46px !important;
padding: 0 22px !important;
border-radius: 8px !important;
border: 1px solid rgba(240, 246, 252, 0.16) !important;
background: rgba(22, 27, 34, 0.6) !important;
color: var(--text-primary) !important;
font-size: 0.92rem !important;
font-weight: 500 !important;
cursor: pointer !important;
box-shadow: none !important;
transition: all 0.2s ease !important;
}
.join-form-content .frm_style_formidable-style.with_frm_style .frm_save_draft:hover,
.join-form-content .frm_style_formidable-style.with_frm_style button[name*="draft"]:hover,
.join-form-content .frm_style_formidable-style.with_frm_style input[name*="draft"]:hover {
background: color-mix(in srgb, var(--bg-card) 74%, var(--color-primary) 26%) !important;
color: #ffffff !important;
.join-form-content .frm_save_draft:hover,
.join-form-content button[name*="draft"]:hover,
.join-form-content input[name*="draft"]:hover {
border-color: var(--color-primary) !important;
background: rgba(56, 139, 253, 0.1) !important;
color: var(--color-primary) !important;
}
/* =========================================
浅色模式适配 (Light Theme)
========================================= */
[data-theme="light"] .join-form-card {
border-color: color-mix(in srgb, #8bbcff 52%, var(--border-default) 48%);
background:
linear-gradient(
118deg,
color-mix(in srgb, #d9eaff 42%, transparent) 0%,
transparent 40%
),
radial-gradient(
140% 90% at 100% 0%,
color-mix(in srgb, #dbe9ff 48%, transparent) 0%,
@@ -1176,16 +1271,134 @@
inset 0 1px 0 rgba(255, 255, 255, 0.7);
}
[data-theme="light"] .join-form-content .frm_style_formidable-style.with_frm_style input[type="text"],
[data-theme="light"] .join-form-content .frm_style_formidable-style.with_frm_style input[type="email"],
[data-theme="light"] .join-form-content .frm_style_formidable-style.with_frm_style input[type="number"],
[data-theme="light"] .join-form-content .frm_style_formidable-style.with_frm_style input[type="tel"],
[data-theme="light"] .join-form-content .frm_style_formidable-style.with_frm_style input[type="date"],
[data-theme="light"] .join-form-content .frm_style_formidable-style.with_frm_style input[type="datetime-local"],
[data-theme="light"] .join-form-content .frm_style_formidable-style.with_frm_style textarea,
[data-theme="light"] .join-form-content .frm_style_formidable-style.with_frm_style select {
[data-theme="light"] .join-form-content input[type="text"],
[data-theme="light"] .join-form-content input[type="email"],
[data-theme="light"] .join-form-content input[type="number"],
[data-theme="light"] .join-form-content input[type="tel"],
[data-theme="light"] .join-form-content input[type="password"],
[data-theme="light"] .join-form-content input[type="date"],
[data-theme="light"] .join-form-content input[type="datetime-local"],
[data-theme="light"] .join-form-content textarea,
[data-theme="light"] .join-form-content select {
background: #ffffff !important;
border-color: color-mix(in srgb, #8bbcff 46%, var(--border-default) 54%) !important;
border: 1px solid #d0d7de !important;
color: #1f2328 !important;
box-shadow: inset 0 1px 2px rgba(31, 35, 40, 0.04) !important;
}
[data-theme="light"] .join-form-content input[type="text"]:hover,
[data-theme="light"] .join-form-content input[type="email"]:hover,
[data-theme="light"] .join-form-content input[type="number"]:hover,
[data-theme="light"] .join-form-content input[type="tel"]:hover,
[data-theme="light"] .join-form-content input[type="password"]:hover,
[data-theme="light"] .join-form-content input[type="date"]:hover,
[data-theme="light"] .join-form-content input[type="datetime-local"]:hover,
[data-theme="light"] .join-form-content textarea:hover,
[data-theme="light"] .join-form-content select:hover {
border-color: #0969da !important;
}
[data-theme="light"] .join-form-content input[type="text"]:focus,
[data-theme="light"] .join-form-content input[type="email"]:focus,
[data-theme="light"] .join-form-content input[type="number"]:focus,
[data-theme="light"] .join-form-content input[type="tel"]:focus,
[data-theme="light"] .join-form-content input[type="password"]:focus,
[data-theme="light"] .join-form-content input[type="date"]:focus,
[data-theme="light"] .join-form-content input[type="datetime-local"]:focus,
[data-theme="light"] .join-form-content textarea:focus,
[data-theme="light"] .join-form-content select:focus {
border-color: #0969da !important;
background: #ffffff !important;
color: #1f2328 !important;
box-shadow: 0 0 0 3px rgba(9, 105, 218, 0.2), inset 0 1px 2px rgba(31, 35, 40, 0.04) !important;
}
[data-theme="light"] .join-form-content input::placeholder,
[data-theme="light"] .join-form-content textarea::placeholder {
color: #8c959f !important;
}
[data-theme="light"] .join-form-content input:-webkit-autofill,
[data-theme="light"] .join-form-content input:-webkit-autofill:hover,
[data-theme="light"] .join-form-content input:-webkit-autofill:focus,
[data-theme="light"] .join-form-content textarea:-webkit-autofill,
[data-theme="light"] .join-form-content textarea:-webkit-autofill:hover,
[data-theme="light"] .join-form-content textarea:-webkit-autofill:focus,
[data-theme="light"] .join-form-content select:-webkit-autofill,
[data-theme="light"] .join-form-content select:-webkit-autofill:hover,
[data-theme="light"] .join-form-content select:-webkit-autofill:focus {
-webkit-text-fill-color: #1f2328 !important;
-webkit-box-shadow: 0 0 0 1000px #ffffff inset !important;
box-shadow: 0 0 0 1000px #ffffff inset !important;
}
[data-theme="light"] .join-form-content .frm_error_style,
[data-theme="light"] .join-form-content .frm_message.frm_error_style,
[data-theme="light"] .join-form-content .frm_error {
background: #ffebe9 !important;
border: 1px solid rgba(207, 34, 46, 0.3) !important;
border-left: 4px solid #cf222e !important;
color: #a40e26 !important;
}
[data-theme="light"] .join-form-content .frm_error_style::before,
[data-theme="light"] .join-form-content .frm_message.frm_error_style::before,
[data-theme="light"] .join-form-content .frm_error::before {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23cf222e' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cline x1='12' y1='8' x2='12' y2='12'%3E%3C/line%3E%3Cline x1='12' y1='16' x2='12.01' y2='16'%3E%3C/line%3E%3C/svg%3E") !important;
}
[data-theme="light"] .join-form-content .frm_message,
[data-theme="light"] .join-form-content .frm_success_style,
[data-theme="light"] .join-form-content .frm_success {
background: #dafbe1 !important;
border: 1px solid rgba(31, 136, 61, 0.3) !important;
border-left: 4px solid #1f883d !important;
color: #1a7f37 !important;
}
[data-theme="light"] .join-form-content .frm_message::before,
[data-theme="light"] .join-form-content .frm_success_style::before,
[data-theme="light"] .join-form-content .frm_success::before {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%231a7f37' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M22 11.08V12a10 10 0 1 1-5.93-9.14'%3E%3C/path%3E%3Cpolyline points='22 4 12 14.01 9 11.01'%3E%3C/polyline%3E%3C/svg%3E") !important;
}
[data-theme="light"] .join-form-content .frm_checkbox label,
[data-theme="light"] .join-form-content .frm_radio label {
border: 1px solid #d0d7de !important;
background: #f6f8fa !important;
}
[data-theme="light"] .join-form-content .frm_checkbox label:hover,
[data-theme="light"] .join-form-content .frm_radio label:hover {
border-color: #0969da !important;
background: rgba(9, 105, 218, 0.06) !important;
}
[data-theme="light"] .join-form-content input[type="submit"],
[data-theme="light"] .join-form-content button.frm_button_submit {
background: linear-gradient(135deg, #0969da 0%, #0550ae 100%) !important;
box-shadow: 0 3px 12px rgba(9, 105, 218, 0.28) !important;
}
[data-theme="light"] .join-form-content input[type="submit"]:hover,
[data-theme="light"] .join-form-content button.frm_button_submit:hover {
box-shadow: 0 6px 18px rgba(9, 105, 218, 0.38) !important;
}
[data-theme="light"] .join-form-content .frm_save_draft,
[data-theme="light"] .join-form-content button[name*="draft"],
[data-theme="light"] .join-form-content input[name*="draft"] {
border: 1px solid #d0d7de !important;
background: #f6f8fa !important;
color: #1f2328 !important;
}
[data-theme="light"] .join-form-content .frm_save_draft:hover,
[data-theme="light"] .join-form-content button[name*="draft"]:hover,
[data-theme="light"] .join-form-content input[name*="draft"]:hover {
border-color: #0969da !important;
background: rgba(9, 105, 218, 0.06) !important;
color: #0969da !important;
}
.join-form-tip {
@@ -13,6 +13,8 @@
let height = 0;
let dpr = 1;
let rafId = null;
let pageVisible = document.visibilityState !== 'hidden';
let heroVisible = true;
const waveDefs = [
{ yRatio: 0.3, amplitude: 24, wavelength: 940, speed: 0.5, alpha: 0.98 },
@@ -45,7 +47,7 @@
};
const resize = () => {
dpr = window.devicePixelRatio || 1;
dpr = Math.min(window.devicePixelRatio || 1, 2);
width = main.clientWidth;
height = Math.max(1, Math.round(getCoverageHeight()));
canvas.width = Math.floor(width * dpr);
@@ -86,6 +88,11 @@
};
const render = (timestamp) => {
if (!pageVisible || !heroVisible || prefersReduced.matches) {
rafId = null;
return;
}
const palette = palettes[getTheme()];
const time = timestamp * 0.001;
ctx.clearRect(0, 0, width, height);
@@ -111,7 +118,7 @@
const start = () => {
stop();
resize();
if (prefersReduced.matches) {
if (prefersReduced.matches || !pageVisible || !heroVisible) {
drawStatic();
return;
}
@@ -136,5 +143,24 @@
window.addEventListener('resize', onResize);
window.addEventListener('load', onResize);
const updateVisibility = () => {
pageVisible = document.visibilityState !== 'hidden';
if (pageVisible && heroVisible) {
start();
} else {
stop();
}
};
document.addEventListener('visibilitychange', updateVisibility);
if (typeof IntersectionObserver !== 'undefined') {
const visibilityObserver = new IntersectionObserver((entries) => {
heroVisible = entries.length === 0 || entries[0].isIntersecting;
updateVisibility();
}, { threshold: 0.01 });
visibilityObserver.observe(canvas);
}
start();
})();
@@ -34,6 +34,8 @@
let trackWidth = 0;
let stageMarkers = [];
let stageLayout = null;
let pageVisible = document.visibilityState !== 'hidden';
let canvasVisible = true;
const waveShape1 = { base: 0.16, amp: 7.5, len: 280, speed: 0.9 };
const waveShape2 = { base: 0.44, amp: 6, len: 340, speed: 0.75 };
@@ -166,7 +168,7 @@
}
function resize() {
dpr = window.devicePixelRatio || 1;
dpr = Math.min(window.devicePixelRatio || 1, 2);
width = canvas.clientWidth;
height = canvas.clientHeight;
canvas.width = Math.max(1, Math.floor(width * dpr));
@@ -245,6 +247,11 @@
}
function renderWaves(timestamp) {
if (!pageVisible || !canvasVisible || prefersReducedMotion.matches) {
rafId = 0;
return;
}
const theme = getTheme();
const palette = palettes[theme];
const time = timestamp * 0.001;
@@ -279,7 +286,7 @@
function startWaves() {
stopWaves();
resize();
if (prefersReducedMotion.matches) {
if (prefersReducedMotion.matches || !pageVisible || !canvasVisible) {
drawStaticWaves();
return;
}
@@ -604,6 +611,25 @@
});
observer.observe(document.documentElement, { attributes: true, attributeFilter: ['data-theme'] });
const updateVisibility = () => {
pageVisible = document.visibilityState !== 'hidden';
if (pageVisible && canvasVisible) {
startWaves();
} else {
stopWaves();
}
};
document.addEventListener('visibilitychange', updateVisibility);
if (typeof IntersectionObserver !== 'undefined') {
const visibilityObserver = new IntersectionObserver((entries) => {
canvasVisible = entries.length === 0 || entries[0].isIntersecting;
updateVisibility();
}, { threshold: 0.01 });
visibilityObserver.observe(canvas);
}
if (typeof prefersReducedMotion.addEventListener === 'function') {
prefersReducedMotion.addEventListener('change', handleMotionPreferenceChange);
} else if (typeof prefersReducedMotion.addListener === 'function') {
@@ -830,8 +856,9 @@
return;
}
const successSelector = '.frm_message:not(.itstudio-otp-status), .frm_success_style, .frm_success';
const updateSuccessMessage = () => {
const successNode = formHost.querySelector('.frm_message, .frm_success_style, .frm_success');
const successNode = formHost.querySelector(successSelector);
if (!successNode) {
return;
}
@@ -843,13 +870,37 @@
const messageCn = resolvedIntent === 'draft' ? '草稿已保存' : '你的报名表单已提交,感谢报名';
const messageEn = resolvedIntent === 'draft' ? 'Draft saved.' : 'Your registration form has been submitted. Thank you for applying.';
const nextText = pickLocaleText(messageCn, messageEn);
if (successNode.dataset.itstudioNoticeIntent === resolvedIntent && successNode.textContent === nextText) {
return;
}
successNode.dataset.itstudioNoticeIntent = resolvedIntent;
successNode.dataset.cn = messageCn;
successNode.dataset.en = messageEn;
successNode.textContent = pickLocaleText(messageCn, messageEn);
successNode.textContent = nextText;
showJoinSubmitNotice(resolvedIntent);
};
const observer = new MutationObserver(updateSuccessMessage);
const observer = new MutationObserver((mutations) => {
const successChanged = mutations.some((mutation) => {
const target = mutation.target && mutation.target.nodeType === 1 ? mutation.target : null;
if (target && (target.matches(successSelector) || target.closest(successSelector))) {
return true;
}
return Array.from(mutation.addedNodes).concat(Array.from(mutation.removedNodes)).some((node) => {
return node.nodeType === 1 && (
node.matches(successSelector) ||
Boolean(node.querySelector && node.querySelector(successSelector))
);
});
});
if (successChanged) {
updateSuccessMessage();
}
});
observer.observe(formHost, { childList: true, subtree: true });
}
@@ -13,6 +13,8 @@
let dpr = 1;
let rafId = null;
let startAt = performance.now();
let pageVisible = document.visibilityState !== 'hidden';
let heroVisible = true;
const EMPTY_SET = new Set();
const WORD_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
@@ -615,12 +617,16 @@
const clamp = (value, min, max) => Math.max(min, Math.min(max, value));
const getTheme = () => (document.documentElement.getAttribute('data-theme') === 'dark' ? 'dark' : 'light');
const tokenCount = (tokens) => tokens.reduce((sum, token) => sum + token[0].length, 0);
const lineCharTotals = codeLines.map((line) => tokenCount(line));
const lineDurations = lineCharTotals.map((chars) => Math.max(150, chars * 8));
const totalTypingDuration = lineDurations.reduce((sum, duration) => sum + duration, 0);
const cycleDuration = totalTypingDuration + 500;
const resizeCanvas = () => {
const rect = hero.getBoundingClientRect();
width = Math.max(1, Math.round(rect.width));
height = Math.max(1, Math.round(rect.height));
dpr = window.devicePixelRatio || 1;
dpr = Math.min(window.devicePixelRatio || 1, 2);
canvas.width = Math.floor(width * dpr);
canvas.height = Math.floor(height * dpr);
canvas.style.width = `${width}px`;
@@ -668,12 +674,6 @@
const baseLineNo = 1;
const scrollLeadLines = 2;
const lineCharTotals = codeLines.map((line) => tokenCount(line));
const lineDurations = lineCharTotals.map((chars) => Math.max(150, chars * 8));
const totalTypingDuration = lineDurations.reduce((sum, duration) => sum + duration, 0);
const holdDuration = 500;
const cycleDuration = totalTypingDuration + holdDuration;
ctx.fillStyle = palette.background;
ctx.fillRect(0, 0, width, height);
ctx.fillStyle = palette.editor;
@@ -683,7 +683,7 @@
ctx.fillStyle = palette.divider;
ctx.fillRect(gutterWidth, 0, 1, height);
const cyclePos = isStatic ? totalTypingDuration + holdDuration : elapsed % cycleDuration;
const cyclePos = isStatic ? totalTypingDuration + 500 : elapsed % cycleDuration;
const writingPhase = cyclePos < totalTypingDuration;
let completedLines = codeLines.length;
@@ -795,6 +795,11 @@
};
const render = (timestamp) => {
if (!pageVisible || !heroVisible || reducedMotionQuery.matches) {
rafId = null;
return;
}
const elapsed = timestamp - startAt;
const palette = themes[getTheme()];
ctx.clearRect(0, 0, width, height);
@@ -817,6 +822,10 @@
const start = () => {
stop();
resizeCanvas();
drawStatic();
if (!pageVisible || !heroVisible || reducedMotionQuery.matches) {
return;
}
startAt = performance.now();
rafId = requestAnimationFrame(render);
};
@@ -848,5 +857,24 @@
window.addEventListener('resize', onResize);
window.addEventListener('load', onResize);
const updateVisibility = () => {
pageVisible = document.visibilityState !== 'hidden';
if (pageVisible && heroVisible) {
start();
} else {
stop();
}
};
document.addEventListener('visibilitychange', updateVisibility);
if (typeof IntersectionObserver !== 'undefined') {
const visibilityObserver = new IntersectionObserver((entries) => {
heroVisible = entries.length === 0 || entries[0].isIntersecting;
updateVisibility();
}, { threshold: 0.01 });
visibilityObserver.observe(hero);
}
start();
})();