mirror of
https://github.com/dreamhunter2333/cloudflare_temp_email.git
synced 2026-09-07 00:17:12 +08:00
fix: improve mobile header menu (#1016)
This commit is contained in:
@@ -24,6 +24,7 @@
|
|||||||
- fix: |Frontend| 收窄地址管理相关弹窗宽度,并让地址表格在弹窗内部横向滚动,避免多地址场景撑宽弹窗
|
- fix: |Frontend| 收窄地址管理相关弹窗宽度,并让地址表格在弹窗内部横向滚动,避免多地址场景撑宽弹窗
|
||||||
- fix: |Frontend| 修复 `/open_api/settings` 未返回 `domains` 数组时前端设置初始化直接调用 `map()` 报 `undefined` 错误的问题,统一按空数组兜底处理
|
- fix: |Frontend| 修复 `/open_api/settings` 未返回 `domains` 数组时前端设置初始化直接调用 `map()` 报 `undefined` 错误的问题,统一按空数组兜底处理
|
||||||
- fix: |Frontend| 修复前端在 `jwt` / `auth` / `adminAuth` 等 localStorage 凭据为空字符串、字面量 `"undefined"` 或包含换行/控制符时,请求构造的 `Authorization` 等头部抛出 `Invalid character in header content` 导致前端所有接口报错的问题(issue #1000)。新增 `safeHeaderValue` / `safeBearerHeader` 工具,对全部认证头做 RFC 7230 校验,不安全的值直接跳过该头部,让 worker 走标准 401 而不是请求级崩溃
|
- fix: |Frontend| 修复前端在 `jwt` / `auth` / `adminAuth` 等 localStorage 凭据为空字符串、字面量 `"undefined"` 或包含换行/控制符时,请求构造的 `Authorization` 等头部抛出 `Invalid character in header content` 导致前端所有接口报错的问题(issue #1000)。新增 `safeHeaderValue` / `safeBearerHeader` 工具,对全部认证头做 RFC 7230 校验,不安全的值直接跳过该头部,让 worker 走标准 401 而不是请求级崩溃
|
||||||
|
- fix: |Frontend| 修复多语言菜单在移动端顶部显示语言与版本按钮导致 Header 横向拥挤或溢出的问题,移动端仅保留菜单按钮并将语言/版本入口放入抽屉
|
||||||
|
|
||||||
### Improvements
|
### Improvements
|
||||||
|
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
- fix: |Frontend| Narrow address-management modal widths and keep address tables horizontally scrollable inside the modal to prevent multi-address lists from stretching the dialog
|
- fix: |Frontend| Narrow address-management modal widths and keep address tables horizontally scrollable inside the modal to prevent multi-address lists from stretching the dialog
|
||||||
- fix: |Frontend| Fix the frontend settings bootstrap throwing an `undefined` error when `/open_api/settings` does not return a `domains` array by normalizing the field to an empty array before mapping it
|
- fix: |Frontend| Fix the frontend settings bootstrap throwing an `undefined` error when `/open_api/settings` does not return a `domains` array by normalizing the field to an empty array before mapping it
|
||||||
- fix: |Frontend| Fix every API call crashing client-side with `Invalid character in header content ["Authorization"]` when stale localStorage credentials (`jwt` / `auth` / `adminAuth` / `userJwt` / `access_token`) are empty, the literal string `"undefined"`, or contain a stray newline or other control character (issue #1000). Adds `safeHeaderValue` / `safeBearerHeader` helpers that validate every auth header against RFC 7230 and omit the header entirely when unsafe, so the worker returns a clean 401 instead of the request being rejected by axios/undici
|
- fix: |Frontend| Fix every API call crashing client-side with `Invalid character in header content ["Authorization"]` when stale localStorage credentials (`jwt` / `auth` / `adminAuth` / `userJwt` / `access_token`) are empty, the literal string `"undefined"`, or contain a stray newline or other control character (issue #1000). Adds `safeHeaderValue` / `safeBearerHeader` helpers that validate every auth header against RFC 7230 and omit the header entirely when unsafe, so the worker returns a clean 401 instead of the request being rejected by axios/undici
|
||||||
|
- fix: |Frontend| Fix the multilingual header on mobile by keeping only the menu button in the top bar and moving language/version actions into the drawer to avoid horizontal crowding or overflow
|
||||||
|
|
||||||
### Improvements
|
### Improvements
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { useIsMobile } from '../utils/composables'
|
|||||||
import {
|
import {
|
||||||
DarkModeFilled, LightModeFilled, MenuFilled,
|
DarkModeFilled, LightModeFilled, MenuFilled,
|
||||||
AdminPanelSettingsFilled, MonitorHeartFilled,
|
AdminPanelSettingsFilled, MonitorHeartFilled,
|
||||||
KeyboardArrowDownOutlined
|
KeyboardArrowDownOutlined, OpenInNewOutlined
|
||||||
} from '@vicons/material'
|
} from '@vicons/material'
|
||||||
import { GithubAlt, Language, User, Home } from '@vicons/fa'
|
import { GithubAlt, Language, User, Home } from '@vicons/fa'
|
||||||
|
|
||||||
@@ -254,13 +254,13 @@ onMounted(async () => {
|
|||||||
<template #extra>
|
<template #extra>
|
||||||
<n-space align="center" class="header-extra">
|
<n-space align="center" class="header-extra">
|
||||||
<n-menu v-if="!isMobile" mode="horizontal" :options="menuOptions" responsive />
|
<n-menu v-if="!isMobile" mode="horizontal" :options="menuOptions" responsive />
|
||||||
<n-button v-else :text="true" @click="showMobileMenu = !showMobileMenu" style="margin-right: 10px;">
|
<n-button v-else :text="true" @click="showMobileMenu = !showMobileMenu">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<n-icon :component="MenuFilled" />
|
<n-icon :component="MenuFilled" />
|
||||||
</template>
|
</template>
|
||||||
{{ t('menu') }}
|
{{ t('menu') }}
|
||||||
</n-button>
|
</n-button>
|
||||||
<n-dropdown :options="languageOptions" @select="changeLocale" trigger="click" class="header-locale-dropdown">
|
<n-dropdown v-if="!isMobile" :options="languageOptions" @select="changeLocale" trigger="click" class="header-locale-dropdown">
|
||||||
<n-button text size="small" class="header-locale-button" style="padding: 0 10px;">
|
<n-button text size="small" class="header-locale-button" style="padding: 0 10px;">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<n-icon :component="Language" />
|
<n-icon :component="Language" />
|
||||||
@@ -270,7 +270,7 @@ onMounted(async () => {
|
|||||||
</n-button>
|
</n-button>
|
||||||
</n-dropdown>
|
</n-dropdown>
|
||||||
<n-button
|
<n-button
|
||||||
v-if="openSettings.showGithub"
|
v-if="!isMobile && openSettings.showGithub"
|
||||||
text
|
text
|
||||||
size="small"
|
size="small"
|
||||||
class="header-version-button"
|
class="header-version-button"
|
||||||
@@ -289,29 +289,26 @@ onMounted(async () => {
|
|||||||
<n-drawer v-model:show="showMobileMenu" placement="top" style="height: 100vh;">
|
<n-drawer v-model:show="showMobileMenu" placement="top" style="height: 100vh;">
|
||||||
<n-drawer-content :title="t('menu')" closable>
|
<n-drawer-content :title="t('menu')" closable>
|
||||||
<n-menu :options="menuOptions" />
|
<n-menu :options="menuOptions" />
|
||||||
<n-dropdown :options="languageOptions" @select="changeLocale" trigger="click" class="header-locale-dropdown">
|
<div class="mobile-menu-actions">
|
||||||
<n-button text class="header-locale-button" style="margin-top: 12px;">
|
<n-dropdown :options="languageOptions" @select="changeLocale" trigger="click" class="header-locale-dropdown">
|
||||||
<template #icon>
|
<button type="button" class="mobile-menu-utility-button">
|
||||||
<n-icon :component="Language" />
|
<n-icon :component="Language" />
|
||||||
</template>
|
<span class="mobile-menu-action-label">{{ currentLocaleLabel }}</span>
|
||||||
{{ currentLocaleLabel }}
|
<n-icon :component="KeyboardArrowDownOutlined" class="mobile-menu-action-arrow" />
|
||||||
<n-icon :component="KeyboardArrowDownOutlined" style="margin-left: 4px;" />
|
</button>
|
||||||
</n-button>
|
</n-dropdown>
|
||||||
</n-dropdown>
|
<a
|
||||||
<n-button
|
v-if="openSettings.showGithub"
|
||||||
v-if="openSettings.showGithub"
|
class="mobile-menu-utility-button"
|
||||||
text
|
target="_blank"
|
||||||
class="header-version-button"
|
rel="noopener noreferrer"
|
||||||
style="margin-top: 12px;"
|
href="https://github.com/dreamhunter2333/cloudflare_temp_email"
|
||||||
tag="a"
|
>
|
||||||
target="_blank"
|
|
||||||
href="https://github.com/dreamhunter2333/cloudflare_temp_email"
|
|
||||||
>
|
|
||||||
<template #icon>
|
|
||||||
<n-icon :component="GithubAlt" />
|
<n-icon :component="GithubAlt" />
|
||||||
</template>
|
<span class="mobile-menu-action-label">{{ version || 'Github' }}</span>
|
||||||
{{ version || 'Github' }}
|
<n-icon :component="OpenInNewOutlined" class="mobile-menu-action-arrow" />
|
||||||
</n-button>
|
</a>
|
||||||
|
</div>
|
||||||
</n-drawer-content>
|
</n-drawer-content>
|
||||||
</n-drawer>
|
</n-drawer>
|
||||||
<n-modal v-model:show="showAuth" :closable="false" :closeOnEsc="false" :maskClosable="false" preset="dialog"
|
<n-modal v-model:show="showAuth" :closable="false" :closeOnEsc="false" :maskClosable="false" preset="dialog"
|
||||||
@@ -337,6 +334,7 @@ onMounted(async () => {
|
|||||||
|
|
||||||
.header-extra {
|
.header-extra {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
flex-wrap: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.header-extra :deep(.n-space-item) {
|
.header-extra :deep(.n-space-item) {
|
||||||
@@ -369,6 +367,46 @@ onMounted(async () => {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mobile-menu-actions {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
|
gap: 6px;
|
||||||
|
margin-top: 12px;
|
||||||
|
padding-top: 12px;
|
||||||
|
border-top: 1px solid rgba(128, 128, 128, 0.16);
|
||||||
|
}
|
||||||
|
|
||||||
|
.mobile-menu-utility-button {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
height: 36px;
|
||||||
|
width: 100%;
|
||||||
|
min-width: 0;
|
||||||
|
padding: 0 8px;
|
||||||
|
border: 0;
|
||||||
|
border-radius: 8px;
|
||||||
|
background: transparent;
|
||||||
|
color: inherit;
|
||||||
|
font: inherit;
|
||||||
|
text-decoration: none;
|
||||||
|
opacity: 0.82;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mobile-menu-action-label {
|
||||||
|
margin: 0 6px;
|
||||||
|
min-width: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mobile-menu-action-arrow {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
margin-left: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
.n-alert {
|
.n-alert {
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
@@ -390,4 +428,17 @@ onMounted(async () => {
|
|||||||
.n-form .n-button {
|
.n-form .n-button {
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media (max-width: 640px) {
|
||||||
|
:deep(.n-page-header__title) {
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.n-page-header__title h3) {
|
||||||
|
max-width: calc(100vw - 136px);
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
Reference in New Issue
Block a user