优化加入我们界面

更新了招新新闻
优化招生进度样式
优化录取进度查询
This commit is contained in:
2026-03-06 21:12:50 +08:00
parent a683ab35d9
commit 11ac498de3
4 changed files with 1968 additions and 192 deletions
+575 -39
View File
@@ -13,6 +13,72 @@
color: var(--color-primary);
}
.join-submit-notice {
margin: -6px 0 14px;
padding: 10px 12px;
border: 1px solid color-mix(in srgb, #2f82ff 42%, var(--border-default) 58%);
border-left-width: 3px;
border-radius: 4px;
background: color-mix(in srgb, #2f82ff 10%, var(--bg-card) 90%);
color: var(--text-primary);
font-size: 0.9rem;
line-height: 1.5;
}
.join-news-strip {
margin-bottom: 20px;
padding: 0 0 10px;
}
.join-news-strip-track {
display: flex;
gap: 14px;
}
.join-news-item {
--join-news-cols: 5;
flex: 0 0 calc((100% - (var(--join-news-cols) - 1) * 14px) / var(--join-news-cols));
width: calc((100% - (var(--join-news-cols) - 1) * 14px) / var(--join-news-cols));
min-width: 0;
padding-right: 12px;
border-right: 1px solid color-mix(in srgb, var(--border-default) 82%, transparent);
}
.join-news-item:last-child {
border-right: 0;
padding-right: 0;
}
.join-news-item-title {
margin: 0;
font-size: 0.94rem;
line-height: 1.38;
font-weight: 700;
}
.join-news-item-title a {
color: var(--text-primary);
text-decoration: none;
}
.join-news-item-title a:hover,
.join-news-item-title a:focus-visible {
color: var(--color-primary);
}
.join-news-item-excerpt {
margin: 7px 0 0;
color: var(--text-secondary);
font-size: 0.82rem;
line-height: 1.5;
}
.join-news-strip-empty {
margin: 0;
color: var(--text-secondary);
font-size: 0.9rem;
}
.join-hero {
display: flex;
flex-direction: column;
@@ -22,7 +88,7 @@
.join-canvas-shell {
position: relative;
border: 1px solid var(--border-default);
height: clamp(280px, 31vw, 440px);
border-radius: 18px;
overflow: hidden;
background: color-mix(in srgb, var(--bg-card) 94%, transparent);
@@ -30,21 +96,25 @@
}
.join-stage-photo-frame {
position: relative;
position: absolute;
inset: 0;
overflow: hidden;
}
.join-stage-photo {
width: 100%;
height: clamp(220px, 28vw, 360px);
height: 100%;
object-fit: cover;
display: block;
}
.join-wave-layer {
position: relative;
margin-top: clamp(-20px, -2.4vw, -12px);
z-index: 1;
position: absolute;
left: 0;
right: 0;
bottom: 0;
margin-top: 0;
z-index: 2;
}
.join-progress-canvas {
@@ -107,11 +177,18 @@
}
.join-wave-mark.is-lighthouse {
width: clamp(22px, 2vw, 30px);
transform: translate(-50%, -80%);
width: clamp(54px, 5.1vw, 81px);
transform: translate(-50%, -82%);
transform-origin: 50% 96%;
}
.join-wave-mark.is-lighthouse.is-docked {
top: auto;
bottom: -1px;
left: auto;
transform: translate(-50%, 0);
}
.join-wave-mark.is-active {
filter: drop-shadow(0 0 10px color-mix(in srgb, var(--color-primary) 36%, transparent));
}
@@ -227,16 +304,105 @@
.join-canvas-overlay {
position: absolute;
top: 16px;
left: 16px;
right: 16px;
z-index: 2;
max-width: 540px;
padding: 14px 16px;
border-radius: 12px;
border: 1px solid color-mix(in srgb, var(--border-default) 72%, transparent);
background: color-mix(in srgb, var(--bg-body) 68%, transparent);
backdrop-filter: blur(6px);
-webkit-backdrop-filter: blur(6px);
left: 0;
right: auto;
width: min(44vw, 360px);
z-index: 3;
isolation: isolate;
overflow: hidden;
max-width: 100%;
padding: 12px 22px 12px 24px;
border-radius: 0;
border: 0;
background: linear-gradient(
90deg,
color-mix(in srgb, var(--bg-body) 78%, transparent) 0%,
color-mix(in srgb, var(--bg-body) 78%, transparent) 34%,
color-mix(in srgb, var(--bg-body) 48%, transparent) 50%,
color-mix(in srgb, var(--bg-body) 16%, transparent) 64%,
rgba(0, 0, 0, 0) 78%,
rgba(0, 0, 0, 0) 100%
);
}
.join-canvas-overlay.is-enter-animate {
animation: join-overlay-slide-in 720ms cubic-bezier(0.2, 0.78, 0.18, 1) both;
will-change: transform, opacity;
}
@keyframes join-overlay-slide-in {
from {
transform: translateX(-112%);
opacity: 0.24;
}
to {
transform: translateX(0);
opacity: 1;
}
}
.join-canvas-overlay::before {
content: "";
position: absolute;
inset: 0;
z-index: 0;
pointer-events: none;
opacity: 0.88;
mix-blend-mode: soft-light;
background:
linear-gradient(
90deg,
rgba(255, 255, 255, 0.12) 0%,
rgba(255, 255, 255, 0.06) 42%,
rgba(255, 255, 255, 0.03) 60%,
rgba(255, 255, 255, 0) 100%
),
repeating-linear-gradient(
135deg,
rgba(255, 255, 255, 0.05) 0 1px,
rgba(255, 255, 255, 0) 1px 3px
),
repeating-linear-gradient(
45deg,
rgba(0, 0, 0, 0.03) 0 1px,
rgba(0, 0, 0, 0) 1px 4px
);
backdrop-filter: blur(9px) saturate(130%);
-webkit-backdrop-filter: blur(9px) saturate(130%);
-webkit-mask-image: linear-gradient(
90deg,
#000 0%,
#000 56%,
rgba(0, 0, 0, 0.6) 66%,
rgba(0, 0, 0, 0) 78%,
rgba(0, 0, 0, 0) 100%
);
mask-image: linear-gradient(
90deg,
#000 0%,
#000 56%,
rgba(0, 0, 0, 0.6) 66%,
rgba(0, 0, 0, 0) 78%,
rgba(0, 0, 0, 0) 100%
);
-webkit-mask-repeat: no-repeat;
mask-repeat: no-repeat;
-webkit-mask-size: 100% 100%;
mask-size: 100% 100%;
}
.join-canvas-overlay > * {
position: relative;
z-index: 1;
}
@media (prefers-reduced-motion: reduce) {
.join-canvas-overlay.is-enter-animate {
animation: none;
transform: none;
opacity: 1;
}
}
.join-current-label {
@@ -259,6 +425,14 @@
color: var(--text-secondary);
}
.join-current-location {
margin: 4px 0 0;
font-size: 0.88rem;
color: color-mix(in srgb, var(--text-primary) 84%, var(--text-secondary) 16%);
line-height: 1.45;
overflow-wrap: anywhere;
}
.join-stage-list {
display: grid;
grid-template-columns: repeat(5, minmax(0, 1fr));
@@ -269,22 +443,77 @@
}
.join-stage-item {
border: 1px solid var(--border-default);
border-radius: 10px;
background: color-mix(in srgb, var(--bg-card) 95%, transparent);
padding: 10px 11px;
position: relative;
border: 1px solid color-mix(in srgb, var(--border-default) 90%, transparent);
border-radius: 4px;
background: linear-gradient(
180deg,
color-mix(in srgb, var(--bg-card) 90%, transparent) 0%,
color-mix(in srgb, var(--bg-card) 97%, transparent) 100%
);
padding: 11px 12px;
min-height: 98px;
overflow: hidden;
transition: border-color 0.22s ease, background 0.22s ease, box-shadow 0.22s ease, transform 0.22s ease;
}
.join-stage-item::before {
content: "";
position: absolute;
left: 0;
right: 0;
top: 0;
height: 2px;
background: color-mix(in srgb, var(--border-default) 75%, transparent);
opacity: 0.86;
}
.join-stage-item.is-active,
.join-stage-item.is-current {
border-color: color-mix(in srgb, var(--color-primary) 52%, var(--border-default) 48%);
box-shadow: var(--shadow-sm);
background: linear-gradient(
180deg,
color-mix(in srgb, var(--color-primary) 10%, var(--bg-card) 90%) 0%,
color-mix(in srgb, var(--bg-card) 96%, transparent) 100%
);
box-shadow:
0 0 0 1px color-mix(in srgb, var(--color-primary) 20%, transparent),
0 12px 22px -18px color-mix(in srgb, var(--color-primary) 46%, transparent);
transform: translateY(-1px);
}
.join-stage-item.is-active::before,
.join-stage-item.is-current::before {
height: 3px;
opacity: 1;
background: linear-gradient(
90deg,
color-mix(in srgb, var(--color-primary) 84%, #7ed7ff 16%) 0%,
color-mix(in srgb, var(--color-primary) 52%, #7ed7ff 48%) 100%
);
}
.join-stage-item.is-completed .join-stage-status {
color: #0f8a4f;
}
.join-stage-item .join-stage-status.is-query-ready {
color: var(--color-primary);
}
.join-stage-item.is-completed {
border-color: color-mix(in srgb, #0f8a4f 48%, var(--border-default) 52%);
background: linear-gradient(
180deg,
color-mix(in srgb, #0f8a4f 7%, var(--bg-card) 93%) 0%,
color-mix(in srgb, var(--bg-card) 96%, transparent) 100%
);
}
.join-stage-item.is-completed::before {
background: color-mix(in srgb, #0f8a4f 65%, transparent);
}
.join-stage-item.is-active .join-stage-status {
color: var(--color-primary);
}
@@ -294,6 +523,34 @@
color: var(--text-secondary);
}
.join-stage-item.is-upcoming,
.join-stage-item.is-pending {
border-color: color-mix(in srgb, var(--border-default) 88%, transparent);
background: linear-gradient(
180deg,
color-mix(in srgb, var(--bg-card) 95%, transparent) 0%,
color-mix(in srgb, var(--bg-card) 99%, transparent) 100%
);
}
.join-stage-item.is-upcoming::after,
.join-stage-item.is-pending::after {
content: "";
position: absolute;
left: 0;
right: 0;
bottom: 0;
height: 24px;
background:
repeating-linear-gradient(
-45deg,
transparent 0 10px,
color-mix(in srgb, var(--border-default) 35%, transparent) 10px 12px
);
opacity: 0.2;
pointer-events: none;
}
.join-stage-title-row {
display: grid;
grid-template-columns: minmax(0, 1fr) auto;
@@ -328,17 +585,34 @@
line-height: 1.45;
}
.join-stage-location {
margin: 4px 0 0;
color: color-mix(in srgb, var(--text-primary) 88%, var(--text-secondary) 12%);
font-size: 0.76rem;
line-height: 1.42;
overflow-wrap: anywhere;
}
.join-forms-grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 16px;
}
.join-forms-grid.is-single {
grid-template-columns: 1fr;
}
.join-form-card {
border: 1px solid var(--border-default);
border: 1px solid color-mix(in srgb, var(--border-default) 86%, transparent);
border-radius: 14px;
background: color-mix(in srgb, var(--bg-card) 95%, transparent);
background: linear-gradient(
145deg,
color-mix(in srgb, var(--bg-card) 82%, #1b2430 18%) 0%,
color-mix(in srgb, var(--bg-card) 94%, transparent) 100%
);
padding: 18px;
box-shadow: 0 16px 30px -24px color-mix(in srgb, #000000 65%, transparent);
}
.join-form-card-full {
@@ -353,8 +627,9 @@
.join-form-head p {
margin: 6px 0 0;
color: var(--text-secondary);
font-size: 0.9rem;
color: color-mix(in srgb, var(--text-primary) 72%, var(--text-secondary) 28%);
font-size: 0.94rem;
line-height: 1.55;
}
.join-form-content {
@@ -365,6 +640,89 @@
margin: 0;
}
.join-progress-query-form {
display: grid;
gap: 12px;
}
.join-progress-query-grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 10px;
}
.join-progress-query-field {
display: grid;
gap: 5px;
}
.join-progress-query-field span {
font-size: 0.82rem;
color: color-mix(in srgb, var(--text-primary) 85%, var(--text-secondary) 15%);
}
.join-progress-query-field input {
width: 100%;
border: 1px solid color-mix(in srgb, var(--border-default) 86%, transparent);
border-radius: 10px;
background: color-mix(in srgb, var(--bg-card) 90%, transparent);
color: var(--text-primary);
padding: 9px 10px;
line-height: 1.3;
}
.join-progress-query-field input:focus {
outline: none;
border-color: color-mix(in srgb, var(--color-primary) 55%, var(--border-default) 45%);
box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-primary) 16%, transparent);
}
.join-progress-query-actions {
display: flex;
justify-content: flex-start;
}
.join-progress-query-submit {
border: 1px solid color-mix(in srgb, var(--color-primary) 48%, var(--border-default) 52%);
border-radius: 10px;
background: color-mix(in srgb, var(--color-primary) 18%, var(--bg-card) 82%);
color: var(--text-primary);
padding: 9px 16px;
font-size: 0.9rem;
font-weight: 600;
cursor: pointer;
}
.join-progress-query-submit:hover {
background: color-mix(in srgb, var(--color-primary) 24%, var(--bg-card) 76%);
}
.join-progress-query-feedback {
margin: 2px 0 0;
padding: 10px 12px;
border-radius: 10px;
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);
font-size: 0.88rem;
line-height: 1.55;
}
.join-progress-query-feedback.is-success {
border-color: color-mix(in srgb, #0f8a4f 58%, var(--border-default) 42%);
background: color-mix(in srgb, #0f8a4f 14%, var(--bg-card) 86%);
}
.join-progress-query-feedback.is-warning {
border-color: color-mix(in srgb, #d89a1b 58%, var(--border-default) 42%);
background: color-mix(in srgb, #d89a1b 14%, var(--bg-card) 86%);
}
.join-progress-query-feedback.is-error {
border-color: color-mix(in srgb, #c34646 58%, var(--border-default) 42%);
background: color-mix(in srgb, #c34646 14%, var(--bg-card) 86%);
}
.join-form-content .frm_forms {
margin: 0;
}
@@ -374,6 +732,62 @@
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_style_formidable-style.with_frm_style .frm_form_field {
margin-bottom: 14px !important;
}
.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;
font-weight: 600 !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_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"],
@@ -382,17 +796,114 @@
.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) 90%, transparent);
border-color: var(--border-default);
color: var(--text-primary);
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;
border-radius: 8px !important;
padding: 10px 12px !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_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;
outline: none !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 {
display: flex !important;
flex-wrap: wrap;
gap: 10px;
align-items: center;
}
.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: 9px;
border: 1px solid color-mix(in srgb, var(--color-primary) 62%, var(--border-default) 38%);
background: color-mix(in srgb, var(--color-primary) 10%, transparent);
color: var(--color-primary);
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;
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);
}
.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 .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;
box-shadow: none !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;
}
[data-theme="light"] .join-form-card {
background: linear-gradient(
145deg,
color-mix(in srgb, #ffffff 94%, #e8f2ff 6%) 0%,
color-mix(in srgb, #ffffff 98%, #e8f2ff 2%) 100%
);
box-shadow: 0 16px 30px -24px rgba(120, 140, 165, 0.35);
}
[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 {
background: #ffffff !important;
border-color: color-mix(in srgb, #8bbcff 46%, var(--border-default) 54%) !important;
}
.join-form-tip {
@@ -422,6 +933,26 @@
padding: 30px 0 60px;
}
.join-news-strip {
margin-bottom: 16px;
}
.join-news-strip-track {
display: flex;
gap: 12px;
overflow-x: auto;
padding-bottom: 6px;
scrollbar-width: thin;
}
.join-news-item {
flex: 0 0 220px;
padding-right: 0;
border-right: 0;
border-bottom: 1px solid color-mix(in srgb, var(--border-default) 82%, transparent);
padding-bottom: 8px;
}
.join-stage-list {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
@@ -446,13 +977,14 @@
.join-canvas-overlay {
top: 12px;
left: 12px;
right: 12px;
padding: 10px 11px;
left: 0;
right: auto;
width: min(86vw, 272px);
padding: 10px 16px 10px 18px;
}
.join-stage-photo {
height: 230px;
.join-canvas-shell {
height: 240px;
}
.join-current-stage {
@@ -472,4 +1004,8 @@
.join-stage-item {
min-height: 0;
}
.join-progress-query-grid {
grid-template-columns: 1fr;
}
}
+155 -18
View File
@@ -16,6 +16,8 @@
const waveFill = document.getElementById('joinWaveFill');
const waveBoat = document.getElementById('joinWaveBoat');
const waveMarks = document.getElementById('joinWaveMarks');
const waveProgress = waveTrack ? waveTrack.closest('.join-wave-progress') : null;
const overlayPanel = document.querySelector('.join-canvas-overlay');
const joinData = window.itstudioJoinData && typeof window.itstudioJoinData === 'object'
? window.itstudioJoinData
: {};
@@ -31,21 +33,24 @@
let trackLeft = 0;
let trackWidth = 0;
let stageMarkers = [];
let stageLayout = null;
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 };
const waveShape3 = { base: 0.68, amp: 6.5, len: 400, speed: 0.62 };
const DAY_MS = 24 * 60 * 60 * 1000;
const ONE_DAY_STAGE_WEIGHT_MS = DAY_MS * 1.8;
const palettes = {
light: {
wave1: 'rgba(198, 227, 255, 0.92)',
wave2: 'rgba(142, 193, 236, 0.4)',
wave3: 'rgba(84, 151, 214, 0.48)',
wave1: 'rgba(122, 178, 230, 0.95)',
wave2: 'rgba(73, 134, 197, 0.72)',
wave3: 'rgba(40, 96, 161, 0.78)',
},
dark: {
wave1: 'rgba(132, 190, 242, 0.88)',
wave2: 'rgba(88, 151, 214, 0.4)',
wave3: 'rgba(56, 118, 183, 0.48)',
wave1: 'rgba(86, 146, 214, 0.92)',
wave2: 'rgba(49, 104, 172, 0.78)',
wave3: 'rgba(27, 73, 136, 0.82)',
},
};
@@ -62,6 +67,61 @@
return Number.isFinite(numeric) ? numeric : null;
}
function getStages() {
return Array.isArray(joinData.stages) ? joinData.stages : [];
}
function getStageDurationMs(stage) {
const start = getNumber(stage ? stage.startTs : null);
const end = getNumber(stage ? stage.endTs : null);
if (start === null || end === null) {
return null;
}
return Math.max(0, end - start);
}
function getEffectiveStageWeightMs(stage) {
const duration = getStageDurationMs(stage);
if (duration === null) {
return ONE_DAY_STAGE_WEIGHT_MS;
}
if (duration <= DAY_MS) {
return ONE_DAY_STAGE_WEIGHT_MS;
}
return duration;
}
function buildStageLayout(stages) {
if (!stages.length) {
return {
markerByIndex: [],
endByIndex: [],
};
}
const weights = stages.map((stage) => getEffectiveStageWeightMs(stage));
const totalWeight = Math.max(1, weights.reduce((sum, w) => sum + w, 0));
const markerByIndex = [];
const endByIndex = [];
let cumulative = 0;
for (let i = 0; i < stages.length; i += 1) {
markerByIndex[i] = clamp(cumulative / totalWeight, 0, 1);
cumulative += weights[i];
endByIndex[i] = clamp(cumulative / totalWeight, 0, 1);
}
endByIndex[endByIndex.length - 1] = 1;
return { markerByIndex, endByIndex };
}
function getStageLayout(stages) {
if (!stageLayout || !stageLayout.markerByIndex || stageLayout.markerByIndex.length !== stages.length) {
stageLayout = buildStageLayout(stages);
}
return stageLayout;
}
function getNavigationType() {
if (window.performance && typeof window.performance.getEntriesByType === 'function') {
const entries = window.performance.getEntriesByType('navigation');
@@ -90,6 +150,21 @@
return getNavigationType() !== 'reload';
}
function setupOverlayEntryAnimation() {
if (!overlayPanel) {
return;
}
overlayPanel.classList.remove('is-enter-animate');
if (!shouldAnimateEntry()) {
return;
}
requestAnimationFrame(() => {
overlayPanel.classList.add('is-enter-animate');
});
}
function resize() {
dpr = window.devicePixelRatio || 1;
width = canvas.clientWidth;
@@ -212,20 +287,34 @@
}
function computeTargetProgress() {
const stages = Array.isArray(joinData.stages) ? joinData.stages : [];
const stages = getStages();
if (!stages.length) {
return 0;
}
const denominator = stages.length > 1 ? (stages.length - 1) : 1;
const layout = getStageLayout(stages);
const markerByIndex = layout.markerByIndex;
const endByIndex = layout.endByIndex;
const currentIndex = getNumber(joinData.currentStageIndex);
const nowTs = getNumber(joinData.nowTs) || Date.now();
// 有进行中阶段时,船严格对齐对应浮标节点
if (currentIndex !== null && currentIndex >= 0) {
return clamp(currentIndex / denominator, 0, 1);
// 有进行中阶段时,在该阶段对应区间内按时间连续推进
if (currentIndex !== null && currentIndex >= 0 && currentIndex < stages.length) {
const stage = stages[currentIndex];
const startProgress = getNumber(markerByIndex[currentIndex]) ?? 0;
const endProgress = getNumber(endByIndex[currentIndex]) ?? startProgress;
const startTs = getNumber(stage ? stage.startTs : null);
const endTs = getNumber(stage ? stage.endTs : null);
if (startTs !== null && endTs !== null && endTs > startTs) {
const ratio = clamp((nowTs - startTs) / (endTs - startTs), 0, 1);
return clamp(startProgress + ((endProgress - startProgress) * ratio), 0, 1);
}
return clamp(startProgress, 0, 1);
}
// 无进行中阶段时,停在最近已完成阶段节点
// 无进行中阶段时,停在最近已完成阶段的末端
let lastCompletedIndex = -1;
for (let i = 0; i < stages.length; i += 1) {
if (stages[i] && stages[i].status === 'completed') {
@@ -233,8 +322,41 @@
}
}
// 阶段空档期:在“上一阶段浮标”和“下一阶段浮标”之间按时间线性推进。
if (lastCompletedIndex >= 0) {
return clamp(lastCompletedIndex / denominator, 0, 1);
let nextUpcomingIndex = -1;
for (let i = lastCompletedIndex + 1; i < stages.length; i += 1) {
if (stages[i] && stages[i].status === 'upcoming') {
nextUpcomingIndex = i;
break;
}
}
if (nextUpcomingIndex >= 0) {
const completedStage = stages[lastCompletedIndex];
const upcomingStage = stages[nextUpcomingIndex];
const gapStartTs = getNumber(completedStage ? completedStage.endTs : null);
const gapEndTs = getNumber(upcomingStage ? upcomingStage.startTs : null);
const fromProgress = clamp(getNumber(markerByIndex[lastCompletedIndex]) ?? 0, 0, 1);
const toProgress = clamp(getNumber(markerByIndex[nextUpcomingIndex]) ?? fromProgress, 0, 1);
if (gapStartTs !== null && gapEndTs !== null && gapEndTs > gapStartTs && nowTs > gapStartTs && nowTs < gapEndTs) {
const gapRatio = clamp((nowTs - gapStartTs) / (gapEndTs - gapStartTs), 0, 1);
return clamp(fromProgress + ((toProgress - fromProgress) * gapRatio), 0, 1);
}
if (nowTs <= gapStartTs) {
return fromProgress;
}
if (nowTs < gapEndTs) {
return clamp((fromProgress + toProgress) * 0.5, 0, 1);
}
}
}
if (lastCompletedIndex >= 0) {
return clamp(getNumber(endByIndex[lastCompletedIndex]) ?? 0, 0, 1);
}
return 0;
@@ -275,23 +397,29 @@
stageMarkers = [];
waveMarks.innerHTML = '';
if (waveProgress) {
waveProgress.querySelectorAll('.join-wave-mark.is-lighthouse.is-docked').forEach((node) => node.remove());
}
const stages = Array.isArray(joinData.stages) ? joinData.stages : [];
const stages = getStages();
if (!stages.length) {
return;
}
const layout = getStageLayout(stages);
const markerByIndex = layout.markerByIndex;
const currentIndex = getNumber(joinData.currentStageIndex);
const safeCurrentIndex = currentIndex === null ? -1 : Math.round(currentIndex);
const denominator = stages.length > 1 ? (stages.length - 1) : 1;
stages.forEach((stage, index) => {
const marker = document.createElement('span');
marker.className = 'join-wave-mark';
const progress = denominator > 0 ? (index / denominator) : 0;
marker.style.left = `${(progress * 100).toFixed(3)}%`;
const isLighthouse = index === stages.length - 1 || (stage && stage.key === 'public_notice');
const progress = isLighthouse
? 1
: clamp(getNumber(markerByIndex[index]) ?? 0, 0, 1);
marker.classList.add(isLighthouse ? 'is-lighthouse' : 'is-buoy');
if (index === safeCurrentIndex) {
marker.classList.add('is-active');
@@ -304,7 +432,15 @@
const beams = isLighthouse ? Array.from(icon.querySelectorAll('.marker-lh-beam')) : [];
waveMarks.appendChild(marker);
if (isLighthouse && waveProgress) {
marker.classList.add('is-docked');
marker.style.right = '';
marker.style.left = 'calc(100% - clamp(18px, 2.2vw, 30px))';
waveProgress.appendChild(marker);
} else {
marker.style.left = `${(progress * 100).toFixed(3)}%`;
waveMarks.appendChild(marker);
}
stageMarkers.push({
element: marker,
icon,
@@ -490,6 +626,7 @@
});
targetProgress = computeTargetProgress();
setupOverlayEntryAnimation();
renderStageMarks();
startWaves();
animateBoatToTarget();