refactor: establish standalone application boundary

This commit is contained in:
leefer
2026-08-03 21:42:25 +08:00
parent cc5fb8d73e
commit e1e76cd51e
324 changed files with 63090 additions and 44743 deletions
+921
View File
@@ -0,0 +1,921 @@
/* Canonical CSS owner: popularity. Historical layers consolidated 2026-08-02. */
.popularity-source-tag {
display: inline-flex;
align-items: center;
min-height: 23px;
padding: 2px 7px;
border: 1px solid var(--line);
border-radius: 4px;
background: var(--surface-muted);
color: var(--text-secondary);
font-size: 12px;
font-weight: 650;
}
.popularity-source-tag.dual {
border-color: rgb(230, 199, 115);
background: var(--amber-soft);
color: rgb(118, 83, 20);
}
.popularity-concepts {
max-width: 320px;
overflow: hidden;
text-overflow: ellipsis;
}
:where(#popularityView) #popularitySummary {
margin-bottom: 12px;
background: rgb(255, 255, 255);
}
#popularityView .data-table {
font-size: 12px;
}
#popularityView .data-table thead th {
height: 32px;
padding: 6px 9px;
font-size: 11.5px;
}
#popularityView .data-table tbody td {
height: 39px;
padding: 5px 9px;
}
.redesigned-popularity-view {
width: min(100%, 2200px);
margin: 0px auto;
padding: 12px 16px 14px;
}
.popularity-page-head-v2 {
min-height: 52px;
display: flex;
align-items: center;
justify-content: space-between;
}
.popularity-title-v2 {
display: flex;
align-items: center;
min-width: 0px;
gap: 9px;
}
.popularity-title-v2 h2 {
margin: 0px;
color: var(--r2-ink);
}
.popularity-title-v2 > span {
color: var(--r2-sub);
font-size: 12px;
}
.popularity-title-v2 > strong {
padding: 4px 8px;
border-radius: 5px;
background: var(--r2-amber-soft);
color: var(--r2-amber);
font-size: 11px;
font-weight: 650;
white-space: nowrap;
}
.popularity-title-v2 > small {
color: var(--r2-faint);
font-size: 10.5px;
white-space: nowrap;
}
.popularity-head-actions-v2 {
display: flex;
align-items: center;
flex: 0 0 auto;
gap: 8px;
}
.popularity-source-tabs-v2 {
display: flex;
align-items: center;
min-height: 34px;
padding: 3px;
border: 1px solid var(--r2-line);
border-radius: 8px;
background: rgb(244, 245, 247);
}
.popularity-source-tabs-v2 button {
min-height: 27px;
padding: 0px 13px;
border: 0px;
border-radius: 5px;
background: transparent;
color: var(--r2-sub);
font-size: 11px;
cursor: pointer;
}
.popularity-source-tabs-v2 button:hover {
color: var(--r2-ink);
}
.popularity-source-tabs-v2 button.active {
background: rgb(255, 255, 255);
color: var(--r2-ink);
font-weight: 700;
box-shadow: rgba(16, 24, 40, 0.09) 0px 1px 3px;
}
.popularity-source-tabs-v2 button:focus-visible {
outline: 2px solid var(--r2-blue);
outline-offset: 1px;
}
.popularity-refresh-v2 {
min-height: 34px;
padding: 0px 11px;
border-radius: 7px;
}
.popularity-refresh-v2 .lucide {
width: 15px;
height: 15px;
}
:where(#popularityView) .popularity-glance-v2 {
display: grid;
grid-template-columns: repeat(3, minmax(0px, 1fr));
gap: 12px;
margin-bottom: 12px;
}
:where(#popularityView) .popularity-glance-v2 article {
min-width: 0px;
min-height: 88px;
display: grid;
align-content: center;
gap: 5px;
position: relative;
overflow: hidden;
padding: 12px 15px;
border: 1px solid var(--r2-line);
border-radius: var(--r2-radius);
}
.popularity-glance-v2 article::before {
content: "";
position: absolute;
inset: 0px auto 0px 0px;
width: 3px;
background: rgb(199, 216, 251);
}
.popularity-glance-v2 article:nth-child(2)::before {
background: rgb(183, 221, 207);
}
.popularity-glance-v2 article.consensus::before {
background: rgb(230, 199, 115);
}
.popularity-glance-v2 article > span {
color: var(--r2-sub);
font-size: 11px;
}
.popularity-glance-v2 article > strong {
overflow: hidden;
color: var(--r2-ink);
font-size: 14px;
font-weight: 750;
text-overflow: ellipsis;
white-space: nowrap;
}
.popularity-glance-v2 article.consensus > strong {
color: var(--r2-amber);
font-size: 18px;
}
.popularity-glance-v2 article > small {
overflow: hidden;
color: var(--r2-faint);
font-size: 10.5px;
text-overflow: ellipsis;
white-space: nowrap;
}
.popularity-table-card-v2 {
min-width: 0px;
min-height: 0px;
display: flex;
flex-direction: column;
overflow: hidden;
border: 1px solid var(--r2-line);
border-radius: var(--r2-radius);
background: rgb(255, 255, 255);
box-shadow: var(--r2-shadow);
}
.popularity-table-head-v2 {
display: flex;
align-items: center;
min-height: 52px;
flex: 0 0 auto;
justify-content: space-between;
gap: 16px;
padding: 8px 13px;
border-bottom: 1px solid var(--r2-line-soft);
}
.popularity-table-head-v2 > div {
display: flex;
align-items: center;
min-width: 0px;
gap: 8px;
}
.popularity-table-head-v2 h3 {
margin: 0px;
color: var(--r2-ink);
font-size: 14px;
font-weight: 750;
white-space: nowrap;
}
.popularity-table-head-v2 > div > span {
overflow: hidden;
color: var(--r2-faint);
font-size: 10.5px;
text-overflow: ellipsis;
white-space: nowrap;
}
.popularity-search-v2 {
display: flex;
align-items: center;
width: 230px;
height: 33px;
flex: 0 0 auto;
gap: 7px;
padding: 0px 10px;
border: 1px solid rgb(216, 221, 229);
border-radius: 7px;
color: var(--r2-faint);
transition: border-color 160ms, box-shadow 160ms;
}
.popularity-search-v2:focus-within {
border-color: rgb(150, 181, 242);
box-shadow: rgba(37, 99, 235, 0.09) 0px 0px 0px 3px;
}
.popularity-search-v2 .lucide {
width: 15px;
height: 15px;
}
.popularity-search-v2 input {
min-width: 0px;
width: 100%;
height: 100%;
padding: 0px;
border: 0px;
outline: 0px;
background: transparent;
color: var(--r2-ink);
font: inherit;
}
.popularity-search-v2 input::placeholder {
color: var(--r2-faint);
}
.popularity-table-frame-v2 {
min-width: 0px;
min-height: 0px;
flex: 1 1 auto;
overflow: auto;
overscroll-behavior: contain;
scrollbar-gutter: stable;
}
.popularity-table-v2 thead th {
position: sticky;
top: 0px;
z-index: 2;
height: 35px;
padding: 7px 10px;
border-bottom-color: var(--r2-line);
color: var(--r2-sub);
font-size: 10.5px;
}
.popularity-table-v2 thead th:nth-child(1) {
width: 78px;
}
.popularity-table-v2 thead th:nth-child(2) {
width: 220px;
}
.popularity-table-v2 thead th:nth-child(3),
.popularity-table-v2 thead th:nth-child(4) {
width: 105px;
}
.popularity-table-v2 thead th:nth-child(5),
.popularity-table-v2 thead th:nth-child(6),
.popularity-table-v2 thead th:nth-child(7) {
width: 115px;
}
.popularity-table-v2 tbody td {
height: 43px;
padding: 7px 10px;
font-size: 11.5px;
}
.popularity-table-v2 tbody tr {
cursor: pointer;
}
.popularity-table-v2 tbody tr:hover {
background: rgb(247, 249, 252);
}
.popularity-rank-v2 {
white-space: nowrap;
}
.popularity-rank-v2 b {
color: var(--r2-ink);
font-size: 12px;
font-weight: 750;
}
.popularity-rank-v2 span {
display: inline-grid;
place-items: center;
width: 20px;
height: 20px;
margin-left: 6px;
border-radius: 5px;
background: var(--r2-up-soft);
color: var(--r2-up);
font-size: 9px;
font-weight: 700;
}
.popularity-stock-v2 {
display: flex;
align-items: center;
min-width: 0px;
gap: 6px;
}
.popularity-stock-v2 strong {
overflow: hidden;
color: var(--r2-ink);
font-size: 12px;
font-weight: 700;
text-overflow: ellipsis;
white-space: nowrap;
}
.popularity-stock-v2 .stock-code {
flex: 0 0 auto;
color: var(--r2-faint);
font-size: 10.5px;
}
.popularity-list-rank-v2 {
color: rgb(64, 85, 115);
}
.popularity-movement-v2 {
font-weight: 650;
}
.popularity-concepts-v2 {
overflow: hidden;
color: var(--r2-sub);
text-overflow: ellipsis;
white-space: nowrap;
}
.popularity-source-tag-v2 {
display: inline-flex;
align-items: center;
min-height: 22px;
padding: 2px 7px;
border-radius: 5px;
background: rgb(243, 244, 246);
color: var(--r2-sub);
font-size: 10px;
white-space: nowrap;
}
.popularity-source-tag-v2.dual {
background: var(--r2-amber-soft);
color: var(--r2-amber);
}
@media (min-width: 721px) {
body[data-active-view="popularityView"] .app-main {
display: flex;
flex-direction: column;
overflow: hidden;
}
body[data-active-view="popularityView"] .overview-strip {
flex: 0 0 auto;
}
body[data-active-view="popularityView"] #popularityView.active-view {
min-height: 0px;
flex: 1 1 auto;
display: flex;
flex-direction: column;
}
}
@media (min-width: 721px) and (max-height: 900px) {
.redesigned-popularity-view {
padding-top: 9px;
padding-bottom: 10px;
}
.popularity-page-head-v2 {
min-height: 45px;
margin-bottom: 7px;
}
.popularity-glance-v2 {
gap: 9px;
margin-bottom: 9px;
}
.popularity-glance-v2 article {
min-height: 76px;
padding-top: 8px;
padding-bottom: 8px;
}
.popularity-table-head-v2 {
min-height: 46px;
}
.popularity-table-v2 tbody td {
height: 39px;
padding-top: 5px;
padding-bottom: 5px;
}
}
@media (max-width: 960px) {
.popularity-title-v2 {
flex-wrap: wrap;
}
.popularity-title-v2 > small {
width: 100%;
}
.popularity-glance-v2 {
grid-template-columns: repeat(2, minmax(0px, 1fr));
}
.popularity-glance-v2 article.consensus {
grid-column: 1 / -1;
}
}
@media (max-width: 720px) {
.redesigned-popularity-view {
padding: 10px;
}
.popularity-page-head-v2 {
flex-direction: column;
}
.popularity-title-v2 {
gap: 6px 8px;
}
.popularity-title-v2 > span {
width: calc(100% - 110px);
}
.popularity-title-v2 > strong {
order: 4;
}
.popularity-title-v2 > small {
order: 5;
width: auto;
}
.popularity-head-actions-v2 {
width: 100%;
}
.popularity-source-tabs-v2 {
min-width: 0px;
flex: 1 1 auto;
}
.popularity-source-tabs-v2 button {
min-width: 0px;
flex: 1 1 auto;
padding-inline: 6px;
}
.popularity-refresh-v2 span {
display: none;
}
.popularity-glance-v2 {
grid-template-columns: minmax(0px, 1fr);
gap: 8px;
}
.popularity-glance-v2 article,
.popularity-glance-v2 article.consensus {
min-height: 74px;
grid-column: auto;
}
.popularity-table-card-v2 {
min-height: 520px;
}
.popularity-table-head-v2 {
align-items: stretch;
flex-direction: column;
gap: 7px;
}
.popularity-table-head-v2 > div {
align-items: flex-start;
flex-direction: column;
gap: 2px;
}
.popularity-search-v2 {
width: 100%;
}
.popularity-table-frame-v2 {
overflow-x: auto;
}
}
@media (prefers-reduced-motion: reduce) {
.popularity-search-v2 {
transition: none;
}
}
.hot3 {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 12px;
margin-bottom: 12px;
}
.hot3 .hc {
background: rgb(255, 255, 255);
border: 1px solid var(--line);
border-radius: var(--radius);
padding: 13px 16px;
box-shadow: var(--shadow);
}
.hot3 .hc .t {
font-size: 12px;
color: var(--sub);
}
.hot3 .hc .n {
font-size: 15px;
font-weight: 800;
margin-top: 4px;
}
.hot3 .hc .d {
font-size: 11px;
color: var(--faint);
margin-top: 4px;
line-height: 1.6;
}
#popularityView .popularity-glance-v2 {
background: var(--bg);
}
#popularityView #popularitySummary {
border: 0px;
border-radius: 0px;
box-shadow: none;
overflow: visible;
}
#popularityView .popularity-glance-v2 article {
background: var(--card);
box-shadow: none;
}
#popularityView .popularity-table-v2 {
table-layout: auto;
min-width: var(--table-medium);
}
#popularityView .popularity-table-v2 th {
width: auto;
}
#popularityView .popularity-table-v2 th:first-child {
width: var(--col-rank);
}
#popularityView .popularity-table-v2 th:nth-child(2) {
width: var(--col-stock);
}
#popularityView .popularity-table-v2 th.number {
width: var(--col-number);
}
@media (min-width: 721px) {
#popularityView .popularity-glance-v2,
#popularityView .popularity-page-head-v2 {
flex: 0 0 auto;
}
#popularityView .popularity-table-card-v2 {
min-height: 0px;
flex: 1 1 auto;
display: flex;
flex-direction: column;
overflow: hidden;
}
#popularityView .popularity-table-frame-v2 {
min-height: 0px;
flex: 1 1 auto;
overflow: auto;
}
}
:root[data-theme="dark"] #popularityView .popularity-glance-v2 {
background: var(--canvas);
}
:root[data-theme="dark"] #popularityView .popularity-glance-v2 article {
border-color: var(--border);
background: var(--surface);
}
:root[data-theme="dark"] #popularityView .popularity-source-tabs-v2 {
border-color: var(--border);
background: var(--surface-muted);
}
:root[data-theme="dark"] #popularityView .popularity-source-tabs-v2 button.active {
background: var(--surface-subtle);
color: var(--text-primary);
box-shadow: var(--control-shadow);
}
+35
View File
@@ -0,0 +1,35 @@
<section id="popularityView" class="workspace-view page redesigned-popularity-view">
<header class="popularity-page-head-v2 lad-head">
<div class="popularity-title-v2">
<h2>人气热榜</h2>
<span>同花顺 × 东方财富双榜</span>
<strong id="popularityDateLabel">--</strong>
<small>涨跌幅为当日行情</small>
</div>
<div class="popularity-head-actions-v2">
<div class="popularity-source-tabs-v2" role="tablist" aria-label="热榜来源">
<button class="active" type="button" role="tab" aria-selected="true" data-popularity-source="combined">双榜综合</button>
<button type="button" role="tab" aria-selected="false" data-popularity-source="ths">同花顺</button>
<button type="button" role="tab" aria-selected="false" data-popularity-source="dc">东方财富</button>
</div>
<button id="popularityRefreshButton" class="button popularity-refresh-v2" type="button" title="刷新热榜"><i data-lucide="refresh-cw"></i><span>刷新</span></button>
</div>
</header>
<div id="popularitySummary" class="popularity-glance-v2 hot3" aria-live="polite"></div>
<section class="popularity-table-card-v2 card">
<header class="popularity-table-head-v2">
<div><h3 id="popularityTableTitle">双榜综合榜</h3><span id="popularityTableNote">按双榜排名综合排序</span></div>
<label class="popularity-search-v2">
<i data-lucide="search" aria-hidden="true"></i>
<span class="visually-hidden">搜索热榜股票</span>
<input id="popularitySearch" type="search" placeholder="搜索代码、名称或概念" autocomplete="off">
</label>
</header>
<div class="popularity-table-frame-v2 tbl-wrap">
<table class="data-table tbl popularity-table-v2"><thead><tr id="popularityTableHead"></tr></thead><tbody id="popularityTableBody"></tbody></table>
<div id="popularityEmpty" class="empty-state" hidden>暂无符合条件的人气数据</div>
</div>
</section>
</section>
+20 -2
View File
@@ -1,8 +1,8 @@
window.XiaobaiPageModules.register("popularity", ["popularityView"], {
bind: bindPopularityEvents,
enter: ["loadPopularity"],
});
/* PRESERVATION-SOURCE-BEGIN app.js:2584-2659 */
async function loadPopularity(force = false) {
if (state.popularityLoading) return;
state.popularityLoading = true;
@@ -79,4 +79,22 @@ function renderPopularityTable() {
document.querySelector("#popularityEmpty").hidden = rows.length > 0;
}
/* PRESERVATION-SOURCE-END app.js:2584-2659 */
function bindPopularityEvents() {
document.querySelector("#popularityRefreshButton").addEventListener("click", () => loadPopularity(true));
document.querySelector("#popularitySearch").addEventListener("input", (event) => {
state.popularityQuery = event.target.value.trim().toLocaleLowerCase("zh-CN");
renderPopularityTable();
});
document.querySelectorAll("[data-popularity-source]").forEach((button) => {
button.addEventListener("click", () => {
state.popularitySource = button.dataset.popularitySource || "combined";
document.querySelectorAll("[data-popularity-source]").forEach((item) => {
const active = item === button;
item.classList.toggle("active", active);
item.setAttribute("aria-selected", String(active));
});
renderPopularityTable();
});
});
}