bc518174
王天杨
提交两个项目文件
|
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
/** 中 / 英 / 藏 欢迎语(与「语言切换」按钮及轮播同步) */
const WELCOME_MESSAGES = [
{
htmlLang: "zh-CN",
label: "中文",
text: "欢迎来到稻城天文台信息查询",
},
{
htmlLang: "en",
label: "English",
text: "Welcome to the Daocheng Observatory Information Query",
},
{
htmlLang: "bo",
label: "བོད་ཡིག",
text: "འདབ་ཆུ་གནམ་གཟིགས་ལྟེ་གནས་ཀྱི་ཆ་འཕྲིན་འཚོལ་ཞིབ་ལ་ཕེབས་པར་དགའ་བསུ་ཞུ།",
},
] as const;
|
bc518174
王天杨
提交两个项目文件
|
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
|
function ArcMenuTile({
item,
index,
total,
}: {
item: MenuItem;
index: number;
total: number;
}) {
const Icon = item.icon;
const clipUid = useId().replace(/:/g, "");
const gradient = TILE_GRADIENTS[index] ?? TILE_GRADIENTS[TILE_GRADIENTS.length - 1];
const isOuterLeft = index === 0;
const isOuterRight = index === total - 1;
const isInnerLeftTrap = index === 1;
const isInnerRightTrap = index === total - 2;
const isOuterEdge = isOuterLeft || isOuterRight;
const isInnerTrap = isInnerLeftTrap || isInnerRightTrap;
/** 中间两块矩形(第 3、4 入口):去掉底部深色叠层,避免倒影里出现黑色遮罩感 */
const isCenterPair = index === 2 || index === 3;
const trapReflectClass = isOuterEdge
? "tile-reflect--trap-outer"
: isInnerTrap
? "tile-reflect--trap-inner"
: "";
const clipLeftId = `tile-arc-l-${clipUid}`;
const clipRightId = `tile-arc-r-${clipUid}`;
const clipInnerLId = `tile-arc-il-${clipUid}`;
const clipInnerRId = `tile-arc-ir-${clipUid}`;
/**
* 中间块高 Hc = 宽×4/3。内梯(2、5)短边 0.868·Hi = Hc,长边 0.932·Hi。
* 外梯(1、6)短边 0.82·Ho 与内梯长边对齐 → Ho = Hc×0.932/(0.868×0.82)。
* 第 3、4 块:矩形 aspect 3/4。
*/
const faceShellClass = isOuterEdge
? "relative h-[calc(min(40vw,9.5rem)*4/3*0.932/0.868/0.82)] w-[min(38vw,9rem)] overflow-hidden shadow-[0_8px_22px_rgba(0,0,0,0.42)] ring-1 ring-white/30 sm:h-[calc(min(36vw,10rem)*4/3*0.932/0.868/0.82)] sm:w-[9.5rem] md:h-[calc(10.25rem*4/3*0.932/0.868/0.82)] md:w-[9.85rem]"
: isInnerTrap
? "relative h-[calc(min(40vw,9.5rem)*4/3/0.868)] w-[min(40vw,9.5rem)] overflow-hidden shadow-[0_8px_22px_rgba(0,0,0,0.42)] ring-1 ring-white/30 sm:h-[calc(min(36vw,10rem)*4/3/0.868)] sm:w-[min(36vw,10rem)] md:h-[calc(10.25rem*4/3/0.868)] md:w-[10.25rem]"
: "relative aspect-[3/4] w-[min(40vw,9.5rem)] overflow-hidden rounded-none shadow-[0_8px_22px_rgba(0,0,0,0.42)] ring-1 ring-white/30 sm:w-[min(36vw,10rem)] md:w-[10.25rem]";
const faceClipStyle: CSSProperties | undefined = isOuterLeft
? { clipPath: `url(#${clipLeftId})` }
: isOuterRight
? { clipPath: `url(#${clipRightId})` }
: isInnerLeftTrap
? { clipPath: `url(#${clipInnerLId})` }
: isInnerRightTrap
? { clipPath: `url(#${clipInnerRId})` }
: undefined;
const face = (
<>
{isOuterLeft ? (
<svg className="pointer-events-none absolute h-0 w-0" aria-hidden focusable={false}>
<defs>
<clipPath id={clipLeftId} clipPathUnits="objectBoundingBox">
<polygon points="0.03,0.027 1,0.09 1,0.91 0.03,0.973" />
</clipPath>
</defs>
</svg>
) : null}
{isOuterRight ? (
<svg className="pointer-events-none absolute h-0 w-0" aria-hidden focusable={false}>
<defs>
<clipPath id={clipRightId} clipPathUnits="objectBoundingBox">
<polygon points="0,0.09 0.97,0.027 0.97,0.973 0,0.91" />
</clipPath>
</defs>
</svg>
) : null}
{isInnerLeftTrap ? (
<svg className="pointer-events-none absolute h-0 w-0" aria-hidden focusable={false}>
<defs>
<clipPath id={clipInnerLId} clipPathUnits="objectBoundingBox">
<polygon points="0.02,0.034 1,0.066 1,0.934 0.02,0.966" />
</clipPath>
</defs>
</svg>
) : null}
{isInnerRightTrap ? (
<svg className="pointer-events-none absolute h-0 w-0" aria-hidden focusable={false}>
<defs>
<clipPath id={clipInnerRId} clipPathUnits="objectBoundingBox">
<polygon points="0,0.066 0.98,0.034 0.98,0.966 0,0.934" />
</clipPath>
</defs>
</svg>
) : null}
<div
className={`menu-tile-face ${isOuterEdge ? "menu-tile--outer" : isInnerTrap ? "menu-tile--inner-trap" : "menu-tile--center"} ${faceShellClass}`}
style={faceClipStyle}
>
<div
className={`absolute inset-0 bg-gradient-to-br ${gradient} saturate-[1.15]`}
/>
<div className="pointer-events-none absolute inset-0 bg-gradient-to-br from-white/30 via-transparent to-transparent" />
<div
className="pointer-events-none absolute inset-0 opacity-[0.38]"
style={{
backgroundImage: `
linear-gradient(135deg, transparent 41%, rgba(255,255,255,0.16) 50%, transparent 59%),
linear-gradient(45deg, transparent 41%, rgba(255,255,255,0.11) 50%, transparent 59%)
`,
}}
/>
{!isCenterPair ? (
<div
className="pointer-events-none absolute inset-0 opacity-90"
style={{
background:
"linear-gradient(118deg, transparent 0%, transparent 38%, rgba(0,0,0,0.12) 52%, rgba(0,0,0,0.28) 100%)",
}}
/>
) : null}
<div className="menu-tile-content relative z-10 flex h-full flex-col items-center justify-center gap-3.5 px-1.5 pb-1.5 pt-1.5 max-md:gap-1.5 max-md:px-1 max-md:py-1 sm:gap-4 sm:px-2 sm:pb-2 sm:pt-2 md:gap-5">
<div
className={`clip-hexagon flex max-md:h-[2.6rem] max-md:w-[2.6rem] shrink-0 items-center justify-center bg-white/[0.26] ring-1 ring-white/45 backdrop-blur-[2px] ${isOuterEdge ? "h-[3.1rem] w-[3.1rem] shadow-[inset_0_0_0_1px_rgba(255,255,255,0.55),inset_0_1px_0_rgba(255,255,255,0.3),0_0_18px_rgba(255,255,255,0.22)] sm:h-[3.55rem] sm:w-[3.55rem]" : "h-[3.2rem] w-[3.2rem] shadow-[inset_0_1px_0_rgba(255,255,255,0.45)] sm:h-[3.75rem] sm:w-[3.75rem]"}`}
>
<Icon
className={`text-white drop-shadow-[0_2px_6px_rgba(0,0,0,0.35)] max-md:h-[1.15rem] max-md:w-[1.15rem] ${isOuterEdge ? "h-[1.45rem] w-[1.45rem] sm:h-[1.65rem] sm:w-[1.65rem]" : "h-[1.5rem] w-[1.5rem] sm:h-8 sm:w-8"}`}
strokeWidth={1.55}
/>
</div>
<span className="max-w-[8rem] text-center text-[10px] font-semibold leading-tight tracking-wide text-white drop-shadow-[0_1px_3px_rgba(0,0,0,0.45)] max-md:max-w-[6.5rem] max-md:leading-snug sm:max-w-[9rem] sm:text-sm">
{item.label}
</span>
</div>
</div>
</>
);
const wrapped = (
<div className="carousel-tile-3d shrink-0 overflow-visible">
<div
className={`tile-reflect relative mx-auto w-max max-md:mb-1 mb-10 md:mb-[5.5rem]${trapReflectClass ? ` ${trapReflectClass}` : ""}${isCenterPair ? " tile-reflect--center-pair" : ""}`}
>
{face}
</div>
</div>
);
if (item.href) {
return (
<a
href={item.href}
target="_blank"
rel="noopener noreferrer"
className="block min-h-0 min-w-0 touch-manipulation overflow-visible outline-none focus-visible:ring-2 focus-visible:ring-white/60 focus-visible:ring-offset-2 focus-visible:ring-offset-transparent"
>
{wrapped}
</a>
);
}
return (
<Link
to={item.to ?? "/"}
className="block min-h-0 min-w-0 touch-manipulation overflow-visible outline-none focus-visible:ring-2 focus-visible:ring-white/60 focus-visible:ring-offset-2 focus-visible:ring-offset-transparent"
>
{wrapped}
</Link>
);
}
function MenuCarouselArc() {
|
3a3dc915
王天杨
feat: 稻城亚丁项目批量更新
|
222
223
224
225
226
227
228
229
230
|
const { t } = useI18n();
const MENU_ITEMS: MenuItem[] = [
{ id: "tour", label: t("nav.tour"), icon: Share2, to: "/tour" },
{ id: "planetarium", label: t("nav.planetarium"), icon: Compass, to: "/planetarium" },
{ id: "wiki", label: t("nav.wiki"), icon: Library, to: "/search" },
{ id: "web", label: t("nav.web"), icon: Globe, to: "/web" },
{ id: "guide", label: t("nav.guide"), icon: BookOpen, to: "/guide" },
{ id: "maintain", label: t("nav.maintain"), icon: Wrench, to: "/admin" },
];
|