@@ -123,7 +123,9 @@ watch(() => props.initialValue, value => {
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
class="p-2 text-slate-400 transition-colors hover:bg-slate-100 hover:text-slate-700"
|
||||
class="oc-icon-button"
|
||||
aria-label="关闭编辑窗口"
|
||||
title="关闭编辑窗口"
|
||||
@click="close"
|
||||
>
|
||||
✕
|
||||
@@ -191,7 +193,7 @@ watch(() => props.initialValue, value => {
|
||||
<button
|
||||
v-if="hasCoordinates"
|
||||
type="button"
|
||||
class="text-xs font-medium text-slate-400 transition-colors hover:text-slate-700"
|
||||
class="oc-text-button oc-text-button--muted text-xs"
|
||||
@click="clearCoordinates"
|
||||
>
|
||||
清空
|
||||
@@ -216,7 +218,7 @@ watch(() => props.initialValue, value => {
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
class="flex h-10 w-10 items-center justify-center border border-sky-200 bg-sky-50 text-sky-700 transition-colors hover:bg-sky-100"
|
||||
class="oc-icon-button oc-icon-button--sky"
|
||||
title="地图选点"
|
||||
aria-label="地图选点"
|
||||
@click="mapPickerOpen = true"
|
||||
|
||||
@@ -187,7 +187,7 @@ onBeforeUnmount(() => {
|
||||
<button
|
||||
type="button"
|
||||
@click="close"
|
||||
class="image-detail-close-button absolute right-4 top-4 z-30 flex h-10 min-h-10 w-10 min-w-10 max-w-10 appearance-none items-center justify-center overflow-hidden border-0 bg-transparent p-0 text-white/70 shadow-none transition-colors hover:text-white [&_svg]:stroke-[2.5]"
|
||||
class="image-detail-close-button oc-overlay-button absolute right-4 top-4 z-30 h-10 w-10 rounded-full [&_svg]:stroke-[2.5]"
|
||||
aria-label="关闭大图"
|
||||
title="关闭大图"
|
||||
>
|
||||
@@ -223,7 +223,7 @@ onBeforeUnmount(() => {
|
||||
<button
|
||||
type="button"
|
||||
@click="toggleInfo"
|
||||
class="absolute bottom-4 right-4 z-30 flex h-11 w-11 items-center justify-center rounded-full bg-transparent text-white drop-shadow-[0_2px_8px_rgba(15,23,42,0.9)] transition-colors hover:text-sky-100"
|
||||
class="oc-overlay-button absolute bottom-4 right-4 z-30 h-11 w-11 rounded-full drop-shadow-[0_2px_8px_rgba(15,23,42,0.9)]"
|
||||
:aria-label="infoOpen ? '隐藏详细信息' : '查看详细信息'"
|
||||
:title="infoOpen ? '隐藏详细信息' : '查看详细信息'"
|
||||
>
|
||||
@@ -254,7 +254,7 @@ onBeforeUnmount(() => {
|
||||
<button
|
||||
type="button"
|
||||
@click="infoOpen = false"
|
||||
class="absolute right-3 top-3 rounded-full p-2 text-slate-400 transition-colors hover:bg-slate-100 hover:text-slate-700"
|
||||
class="oc-icon-button oc-icon-button--small absolute right-3 top-3 rounded-full"
|
||||
aria-label="隐藏详细信息"
|
||||
title="隐藏详细信息"
|
||||
>
|
||||
|
||||
@@ -158,7 +158,9 @@ onBeforeUnmount(() => {
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
class="p-2 text-slate-400 transition-colors hover:bg-slate-100 hover:text-slate-700"
|
||||
class="oc-icon-button"
|
||||
aria-label="关闭地图选点窗口"
|
||||
title="关闭地图选点窗口"
|
||||
@click="close"
|
||||
>
|
||||
✕
|
||||
|
||||
@@ -77,7 +77,7 @@ async function initializeMap() {
|
||||
marker = new amapLib.Marker({
|
||||
position: center.value,
|
||||
title: props.locationName || '拍摄位置',
|
||||
content: '<div class="h-4 w-4 rounded-full border-2 border-white bg-teal-500 shadow-[0_0_0_4px_rgba(20,184,166,0.22)]"></div>',
|
||||
content: '<div class="h-4 w-4 rounded-full border-2 border-white bg-teal-500 shadow-[0_0_0_4px_rgba(52,116,93,0.24)]"></div>',
|
||||
offset: new amapLib.Pixel(-8, -8),
|
||||
} as AMap.MarkerOptions)
|
||||
marker.setMap(mapInstance)
|
||||
|
||||
@@ -207,7 +207,7 @@ onBeforeUnmount(() => {
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
class="quick-upload-close flex h-9 w-9 items-center justify-center border border-slate-200 bg-slate-50 text-slate-500 transition-colors hover:bg-slate-100 hover:text-slate-800"
|
||||
class="quick-upload-close oc-icon-button"
|
||||
aria-label="关闭快捷上传"
|
||||
title="关闭快捷上传"
|
||||
@click="close"
|
||||
@@ -252,8 +252,8 @@ onBeforeUnmount(() => {
|
||||
<img :src="activeItem.preview" alt="图片预览" class="h-56 w-full object-contain" />
|
||||
</div>
|
||||
<div class="mt-3 flex items-center justify-between gap-2">
|
||||
<button type="button" class="text-sm font-medium text-sky-700 hover:text-sky-900" @click="fileInput?.click()">重新选择</button>
|
||||
<button type="button" class="text-sm font-medium text-rose-600 hover:text-rose-800" @click="handleRemove(activeItem.id)">移除</button>
|
||||
<button type="button" class="oc-text-button text-sm" @click="fileInput?.click()">重新选择</button>
|
||||
<button type="button" class="oc-text-button oc-text-button--danger text-sm" @click="handleRemove(activeItem.id)">移除</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -320,7 +320,7 @@ onBeforeUnmount(() => {
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
class="flex h-10 w-10 items-center justify-center border border-sky-200 bg-sky-50 text-sky-700 transition-colors hover:bg-sky-100"
|
||||
class="oc-icon-button oc-icon-button--sky"
|
||||
title="地图选点"
|
||||
aria-label="地图选点"
|
||||
@click="openMapPicker"
|
||||
|
||||
@@ -138,7 +138,7 @@ async function handleLogout() {
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="flex h-16 items-center justify-between">
|
||||
<RouterLink to="/" class="flex items-center gap-3">
|
||||
<div class="flex h-10 w-10 items-center justify-center border border-slate-300 bg-[linear-gradient(135deg,#ecfeff_0%,#ccfbf1_100%)] shadow-[4px_4px_0_0_rgba(15,23,42,0.08)]">
|
||||
<div class="flex h-10 w-10 items-center justify-center border border-sky-200 bg-sky-100 shadow-[4px_4px_0_0_rgba(15,23,42,0.08)]">
|
||||
<svg
|
||||
class="h-8 w-8"
|
||||
viewBox="0 0 16 16"
|
||||
@@ -173,21 +173,21 @@ async function handleLogout() {
|
||||
<nav class="hidden items-center gap-2 border border-slate-200 bg-white px-2 py-2 shadow-[6px_6px_0_0_rgba(15,23,42,0.05)] md:flex">
|
||||
<RouterLink
|
||||
to="/"
|
||||
class="px-3 py-2 text-sm font-medium tracking-[0.12em] uppercase transition-colors"
|
||||
class="oc-nav-link"
|
||||
:class="route.name === 'map' ? activeNavClass : inactiveNavClass"
|
||||
>
|
||||
地图
|
||||
</RouterLink>
|
||||
<RouterLink
|
||||
to="/community"
|
||||
class="px-3 py-2 text-sm font-medium tracking-[0.12em] uppercase transition-colors"
|
||||
class="oc-nav-link"
|
||||
:class="route.name === 'community' ? activeNavClass : inactiveNavClass"
|
||||
>
|
||||
社区
|
||||
</RouterLink>
|
||||
<RouterLink
|
||||
to="/gallery"
|
||||
class="px-3 py-2 text-sm font-medium tracking-[0.12em] uppercase transition-colors"
|
||||
class="oc-nav-link"
|
||||
:class="route.name === 'gallery' ? activeNavClass : inactiveNavClass"
|
||||
>
|
||||
画廊
|
||||
@@ -195,7 +195,7 @@ async function handleLogout() {
|
||||
<RouterLink
|
||||
v-if="authStore.isLoggedIn"
|
||||
to="/encyclopedia"
|
||||
class="px-3 py-2 text-sm font-medium tracking-[0.12em] uppercase transition-colors"
|
||||
class="oc-nav-link"
|
||||
:class="route.name === 'encyclopedia' || route.name === 'cloud-type' ? activeNavClass : inactiveNavClass"
|
||||
>
|
||||
图鉴
|
||||
@@ -210,7 +210,7 @@ async function handleLogout() {
|
||||
class="no-underline"
|
||||
>
|
||||
<span
|
||||
class="inline-flex h-8 items-center border border-sky-200 bg-sky-100 px-3 text-sm font-medium uppercase tracking-[0.12em] text-sky-800 shadow-[4px_4px_0_0_rgba(14,165,233,0.14)] transition-[background-color,color,transform,box-shadow] hover:-translate-x-px hover:-translate-y-px hover:bg-sky-50 hover:text-sky-900 hover:shadow-[5px_5px_0_0_rgba(14,165,233,0.18)] md:h-10 md:px-4"
|
||||
class="oc-header-button oc-header-button--sky uppercase tracking-[0.12em]"
|
||||
:class="route.name === 'upload' ? 'ring-1 ring-sky-300' : ''"
|
||||
>
|
||||
上传
|
||||
@@ -227,8 +227,8 @@ async function handleLogout() {
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
class="inline-flex h-8 max-w-[8.5rem] items-center gap-2 border border-teal-100 bg-white/80 px-3 text-sm font-medium text-teal-700 shadow-[3px_3px_0_0_rgba(20,184,166,0.08)] transition-[background-color,color,transform,box-shadow,border-color] hover:-translate-x-px hover:-translate-y-px hover:border-teal-200 hover:bg-teal-50/70 hover:text-teal-800 hover:shadow-[4px_4px_0_0_rgba(20,184,166,0.12)] md:h-10 md:max-w-none"
|
||||
:class="route.name === 'profile' || route.name === 'profile-settings' ? 'border-teal-200 bg-teal-50/80 text-teal-800 ring-1 ring-teal-200 shadow-[4px_4px_0_0_rgba(20,184,166,0.12)]' : ''"
|
||||
class="oc-header-button oc-header-button--teal max-w-[8.5rem] gap-2 md:max-w-none"
|
||||
:class="route.name === 'profile' || route.name === 'profile-settings' ? 'border-teal-200 bg-teal-50/80 text-teal-800 ring-1 ring-teal-200 shadow-[4px_4px_0_0_rgba(52,116,93,0.16)]' : ''"
|
||||
aria-haspopup="menu"
|
||||
:aria-expanded="accountCardOpen"
|
||||
>
|
||||
@@ -244,9 +244,9 @@ async function handleLogout() {
|
||||
role="menu"
|
||||
>
|
||||
<div class="border border-slate-200 bg-white shadow-[8px_8px_0_0_rgba(15,23,42,0.08)]">
|
||||
<div class="border-b border-slate-200 bg-[linear-gradient(180deg,#f0fdfa_0%,#ffffff_100%)] px-4 py-4">
|
||||
<div class="border-b border-slate-200 bg-[linear-gradient(180deg,#f2faf6_0%,#ffffff_100%)] px-4 py-4">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="flex h-11 w-11 shrink-0 items-center justify-center border border-teal-200 bg-[linear-gradient(135deg,#ecfeff_0%,#ccfbf1_100%)] text-lg font-bold text-teal-800">
|
||||
<div class="flex h-11 w-11 shrink-0 items-center justify-center border border-teal-200 bg-[linear-gradient(135deg,#eef9f3_0%,#d9efe3_100%)] text-lg font-bold text-teal-800">
|
||||
{{ displayUsername.slice(0, 1).toUpperCase() }}
|
||||
</div>
|
||||
<div class="min-w-0">
|
||||
@@ -265,7 +265,7 @@ async function handleLogout() {
|
||||
<div class="py-2">
|
||||
<RouterLink
|
||||
to="/profile"
|
||||
class="flex items-center gap-3 px-4 py-2.5 text-sm font-medium text-slate-700 transition-colors hover:bg-teal-50 hover:text-teal-800"
|
||||
class="oc-menu-item"
|
||||
role="menuitem"
|
||||
>
|
||||
<NIcon size="18"><User /></NIcon>
|
||||
@@ -273,7 +273,7 @@ async function handleLogout() {
|
||||
</RouterLink>
|
||||
<RouterLink
|
||||
to="/profile/settings"
|
||||
class="flex items-center gap-3 px-4 py-2.5 text-sm font-medium text-slate-700 transition-colors hover:bg-teal-50 hover:text-teal-800"
|
||||
class="oc-menu-item"
|
||||
role="menuitem"
|
||||
>
|
||||
<NIcon size="18"><Settings /></NIcon>
|
||||
@@ -282,7 +282,7 @@ async function handleLogout() {
|
||||
<RouterLink
|
||||
v-if="authStore.isAdmin"
|
||||
to="/admin"
|
||||
class="flex items-center gap-3 px-4 py-2.5 text-sm font-medium text-slate-700 transition-colors hover:bg-amber-50 hover:text-amber-700"
|
||||
class="oc-menu-item oc-menu-item--amber"
|
||||
role="menuitem"
|
||||
>
|
||||
<NIcon size="18"><Shield /></NIcon>
|
||||
@@ -293,7 +293,7 @@ async function handleLogout() {
|
||||
<div class="border-t border-slate-200 p-2">
|
||||
<button
|
||||
type="button"
|
||||
class="flex w-full items-center gap-3 px-2 py-2.5 text-left text-sm font-medium text-rose-600 transition-colors hover:bg-rose-50 hover:text-rose-700"
|
||||
class="oc-menu-item oc-menu-item--danger px-2"
|
||||
role="menuitem"
|
||||
@click="handleLogout"
|
||||
>
|
||||
@@ -312,7 +312,7 @@ async function handleLogout() {
|
||||
class="no-underline"
|
||||
>
|
||||
<span
|
||||
class="inline-flex h-8 items-center border border-slate-200 bg-white/80 px-3 text-sm font-medium text-slate-700 shadow-[3px_3px_0_0_rgba(15,23,42,0.06)] transition-[background-color,color,transform,box-shadow,border-color] hover:-translate-x-px hover:-translate-y-px hover:border-teal-200 hover:bg-teal-50 hover:text-teal-800 hover:shadow-[4px_4px_0_0_rgba(15,23,42,0.08)] md:h-10 md:px-4"
|
||||
class="oc-header-button oc-header-button--neutral"
|
||||
:class="route.name === 'login' ? 'bg-teal-50 ring-0 ring-teal-100 text-teal-800' : ''"
|
||||
>
|
||||
登录
|
||||
@@ -323,7 +323,7 @@ async function handleLogout() {
|
||||
class="no-underline"
|
||||
>
|
||||
<span
|
||||
class="inline-flex h-8 items-center border border-sky-200 bg-sky-100 px-3 text-sm font-medium text-sky-800 shadow-[4px_4px_0_0_rgba(14,165,233,0.14)] transition-[background-color,color,transform,box-shadow] hover:-translate-x-px hover:-translate-y-px hover:bg-sky-50 hover:text-sky-900 hover:shadow-[5px_5px_0_0_rgba(14,165,233,0.18)] md:h-10 md:px-4"
|
||||
class="oc-header-button oc-header-button--sky"
|
||||
:class="route.name === 'register' ? 'ring-0 ring-sky-300' : ''"
|
||||
>
|
||||
注册
|
||||
@@ -337,21 +337,21 @@ async function handleLogout() {
|
||||
<nav class="flex items-center gap-2 overflow-x-auto border-t border-slate-200/80 py-2 md:hidden">
|
||||
<RouterLink
|
||||
to="/"
|
||||
class="shrink-0 px-3 py-2 text-sm font-medium tracking-[0.12em] uppercase transition-colors"
|
||||
class="oc-nav-link shrink-0"
|
||||
:class="route.name === 'map' ? activeNavClass : inactiveNavClass"
|
||||
>
|
||||
地图
|
||||
</RouterLink>
|
||||
<RouterLink
|
||||
to="/community"
|
||||
class="shrink-0 px-3 py-2 text-sm font-medium tracking-[0.12em] uppercase transition-colors"
|
||||
class="oc-nav-link shrink-0"
|
||||
:class="route.name === 'community' ? activeNavClass : inactiveNavClass"
|
||||
>
|
||||
社区
|
||||
</RouterLink>
|
||||
<RouterLink
|
||||
to="/gallery"
|
||||
class="shrink-0 px-3 py-2 text-sm font-medium tracking-[0.12em] uppercase transition-colors"
|
||||
class="oc-nav-link shrink-0"
|
||||
:class="route.name === 'gallery' ? activeNavClass : inactiveNavClass"
|
||||
>
|
||||
画廊
|
||||
@@ -359,7 +359,7 @@ async function handleLogout() {
|
||||
<RouterLink
|
||||
v-if="authStore.isLoggedIn"
|
||||
to="/encyclopedia"
|
||||
class="shrink-0 px-3 py-2 text-sm font-medium tracking-[0.12em] uppercase transition-colors"
|
||||
class="oc-nav-link shrink-0"
|
||||
:class="route.name === 'encyclopedia' || route.name === 'cloud-type' ? activeNavClass : inactiveNavClass"
|
||||
>
|
||||
图鉴
|
||||
@@ -367,7 +367,7 @@ async function handleLogout() {
|
||||
<RouterLink
|
||||
v-if="!authStore.loading && authStore.isLoggedIn"
|
||||
to="/profile"
|
||||
class="shrink-0 px-3 py-2 text-sm font-medium tracking-[0.12em] uppercase transition-colors"
|
||||
class="oc-nav-link shrink-0"
|
||||
:class="route.name === 'profile' ? activeNavClass : inactiveNavClass"
|
||||
>
|
||||
主页
|
||||
@@ -379,7 +379,7 @@ async function handleLogout() {
|
||||
<button
|
||||
v-if="headerHidden"
|
||||
type="button"
|
||||
class="absolute left-1/2 top-3 flex -translate-x-1/2 items-center gap-2 border border-slate-300 bg-white/94 px-3 py-1.5 text-xs font-medium tracking-[0.16em] text-slate-700 shadow-[4px_4px_0_0_rgba(15,23,42,0.08)] backdrop-blur transition-colors hover:border-slate-900 hover:text-slate-900"
|
||||
class="absolute left-1/2 top-3 flex -translate-x-1/2 items-center gap-2 border border-slate-300 bg-white/94 px-3 py-1.5 text-xs font-medium tracking-[0.16em] text-slate-700 shadow-[4px_4px_0_0_rgba(15,23,42,0.08)] backdrop-blur transition-colors hover:border-teal-300 hover:bg-teal-50 hover:text-teal-900 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-sky-600"
|
||||
@click="showHeader(true)"
|
||||
>
|
||||
<span>▼</span>
|
||||
|
||||
@@ -379,7 +379,7 @@ function formatMonthTooltip(monthKey: string) {
|
||||
v-for="cell in week"
|
||||
:key="cell.date"
|
||||
type="button"
|
||||
class="relative h-3.5 w-3.5 border transition-transform hover:scale-125"
|
||||
class="oc-heatmap-cell relative h-3.5 w-3.5 border hover:scale-125"
|
||||
:class="[
|
||||
getCellClass(cell),
|
||||
props.activeDate === cell.date ? 'ring-2 ring-slate-900 ring-offset-1' : '',
|
||||
|
||||
Reference in New Issue
Block a user