feat(mobile): redesign vote page header layout
- Move username to top-left position - Center the page title - Move logout button to bottom-left - Show connection status with latency on top-right Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -63,26 +63,26 @@ onMounted(() => {
|
|||||||
<div class="sticky-header">
|
<div class="sticky-header">
|
||||||
<!-- Header -->
|
<!-- Header -->
|
||||||
<header class="page-header">
|
<header class="page-header">
|
||||||
<div class="header-left">
|
<!-- 第一行:昵称 | 节目投票 | 连接状态 -->
|
||||||
|
<div class="header-row header-row-top">
|
||||||
|
<span class="user-name">{{ connectionStore.userName || '访客' }}</span>
|
||||||
<h1 class="page-title">节目投票</h1>
|
<h1 class="page-title">节目投票</h1>
|
||||||
<div class="header-info">
|
<span class="status-indicator" :class="{ active: connectionStore.isConnected }">
|
||||||
<span class="user-name">{{ connectionStore.userName || '访客' }}</span>
|
<span class="status-dot" :class="{ pulsing: connectionStore.isConnected }"></span>
|
||||||
<span class="info-divider">·</span>
|
已连接 {{ connectionStore.latency }}ms
|
||||||
<span class="status-indicator" :class="{ active: votingStore.votingOpen }">
|
</span>
|
||||||
<span class="status-dot" :class="{ pulsing: votingStore.votingOpen }"></span>
|
|
||||||
{{ votingStatusMessage }}
|
|
||||||
</span>
|
|
||||||
<span class="info-divider">·</span>
|
|
||||||
<span class="logout-btn" @click="handleLogout">退出</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="progress-ring">
|
<!-- 第二行:退出 | 进度环 -->
|
||||||
<svg viewBox="0 0 36 36" class="circular-progress">
|
<div class="header-row header-row-bottom">
|
||||||
<path class="circle-bg" d="M18 2.0845 a 15.9155 15.9155 0 0 1 0 31.831 a 15.9155 15.9155 0 0 1 0 -31.831" />
|
<span class="logout-btn" @click="handleLogout">退出</span>
|
||||||
<path class="circle-progress" :stroke-dasharray="`${votingStore.totalTicketCount > 0 ? (votingStore.usedTicketCount / votingStore.totalTicketCount) * 100 : 0}, 100`"
|
<div class="progress-ring">
|
||||||
d="M18 2.0845 a 15.9155 15.9155 0 0 1 0 31.831 a 15.9155 15.9155 0 0 1 0 -31.831" />
|
<svg viewBox="0 0 36 36" class="circular-progress">
|
||||||
</svg>
|
<path class="circle-bg" d="M18 2.0845 a 15.9155 15.9155 0 0 1 0 31.831 a 15.9155 15.9155 0 0 1 0 -31.831" />
|
||||||
<span class="progress-text">{{ votingStore.usedTicketCount }}/{{ votingStore.totalTicketCount }}</span>
|
<path class="circle-progress" :stroke-dasharray="`${votingStore.totalTicketCount > 0 ? (votingStore.usedTicketCount / votingStore.totalTicketCount) * 100 : 0}, 100`"
|
||||||
|
d="M18 2.0845 a 15.9155 15.9155 0 0 1 0 31.831 a 15.9155 15.9155 0 0 1 0 -31.831" />
|
||||||
|
</svg>
|
||||||
|
<span class="progress-text">{{ votingStore.usedTicketCount }}/{{ votingStore.totalTicketCount }}</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
</div>
|
</div>
|
||||||
@@ -127,21 +127,46 @@ onMounted(() => {
|
|||||||
background: $color-surface-glass;
|
background: $color-surface-glass;
|
||||||
backdrop-filter: $backdrop-blur;
|
backdrop-filter: $backdrop-blur;
|
||||||
-webkit-backdrop-filter: $backdrop-blur;
|
-webkit-backdrop-filter: $backdrop-blur;
|
||||||
padding: $spacing-lg;
|
padding: $spacing-md $spacing-lg;
|
||||||
padding-top: calc(env(safe-area-inset-top) + #{$spacing-lg});
|
padding-top: calc(env(safe-area-inset-top) + #{$spacing-md});
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.header-left {
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 4px;
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-row-top {
|
||||||
|
.user-name {
|
||||||
|
flex: 1;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
.page-title {
|
||||||
|
flex: 1;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.status-indicator {
|
||||||
|
flex: 1;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-row-bottom {
|
||||||
|
.logout-btn {
|
||||||
|
flex: 1;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
.progress-ring {
|
||||||
|
// 保持右侧
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.page-title {
|
.page-title {
|
||||||
font-size: $font-size-2xl;
|
font-size: $font-size-lg;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
color: $color-text-inverse;
|
color: $color-text-inverse;
|
||||||
}
|
}
|
||||||
@@ -151,22 +176,12 @@ onMounted(() => {
|
|||||||
color: $color-gold;
|
color: $color-gold;
|
||||||
}
|
}
|
||||||
|
|
||||||
.header-info {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 6px;
|
|
||||||
font-size: $font-size-sm;
|
|
||||||
}
|
|
||||||
|
|
||||||
.info-divider {
|
|
||||||
color: rgba(255, 255, 255, 0.3);
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-indicator {
|
.status-indicator {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 4px;
|
gap: 4px;
|
||||||
color: $color-text-secondary;
|
color: $color-text-secondary;
|
||||||
|
font-size: $font-size-xs;
|
||||||
|
|
||||||
&.active {
|
&.active {
|
||||||
color: #22c55e;
|
color: #22c55e;
|
||||||
|
|||||||
Reference in New Issue
Block a user