index.vue 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583
  1. <template>
  2. <div :class="['layout', THEME_MAP[themeIdx]]">
  3. <Accessibility
  4. ref="accessibility"
  5. @show="loveSwitch = true"
  6. @hide="loveSwitch = false"
  7. />
  8. <div class="aria-control-target layout-main">
  9. <!-- 顶部top -->
  10. <div class="topnav-wrap">
  11. <div class="topnav">
  12. <div class="topnav-container">
  13. <img
  14. :src="
  15. [
  16. THEME_COLOR.DEFAULT,
  17. THEME_COLOR.BLUE,
  18. THEME_COLOR.BLACK,
  19. ].includes(themeIdx)
  20. ? Logo
  21. : Logo2
  22. "
  23. aria-label="Image"
  24. aria-description="CAPTIAL MUSEUM.CHINA"
  25. />
  26. <ul
  27. class="topnav-list"
  28. data-aria-navigation-area
  29. aria-description="You have reached the horizontal menu at the top of the website. There are eight dropdown menus and 34 options in this section. To browse the content, please use the tab key."
  30. >
  31. <li
  32. v-for="item in topData.filter((i) => !i.hideNav)"
  33. :key="item.id"
  34. tabindex="0"
  35. aria-label="Link"
  36. :aria-description="item.name"
  37. :class="{
  38. active:
  39. $route.path
  40. .toLowerCase()
  41. .indexOf(((item.routeParams as RouteLocationNamedRaw)!.name as string).toLowerCase()) > -1,
  42. }"
  43. @click="$router.push(item.routeParams!)"
  44. @keydown.enter.passive="$router.push(item.routeParams!)"
  45. >
  46. <span>{{ item.name }}</span>
  47. <ul class="main_nav_sub">
  48. <li
  49. v-for="(val, index) in item.children"
  50. :key="index"
  51. tabindex="0"
  52. :class="{ active2: $route.path === val.routeParams }"
  53. aria-label="Link"
  54. :aria-description="val.name"
  55. @click.stop="$router.push(val.routeParams!)"
  56. @keydown.enter.passive.stop="$router.push(val.routeParams!)"
  57. >
  58. <span>{{ val.name }}</span>
  59. </li>
  60. </ul>
  61. </li>
  62. <!-- 中文网 -->
  63. <li class="language" aria-description="English">
  64. <a
  65. href="http://www.capitalmuseum.org.cn/"
  66. target="_blank"
  67. aria-description="Chinese"
  68. >
  69. 中文
  70. </a>
  71. </li>
  72. <!-- 爱心模式 -->
  73. <li class="love">
  74. <p @click="loveSwitch = !loveSwitch">Assistive Mode</p>
  75. <van-switch
  76. v-model="loveSwitch"
  77. active-color="var(--van-primary-color)"
  78. inactive-color="#dcdfe6"
  79. aria-label="Button"
  80. aria-description="Assistive Mode"
  81. />
  82. </li>
  83. </ul>
  84. <!-- 搜索 -->
  85. <div
  86. class="search"
  87. data-aria-interaction-area
  88. aria-description="You've reached the search field, please use the tab key to browse the content."
  89. >
  90. <template v-if="$route.name !== 'Search'">
  91. <input
  92. v-model="searchTxt"
  93. placeholder="search..."
  94. @keyup.enter="handleSearch(searchTxt)"
  95. />
  96. <svg-icon
  97. name="search"
  98. color="var(--van-primary-color)"
  99. @click="handleSearch(searchTxt)"
  100. />
  101. </template>
  102. </div>
  103. </div>
  104. </div>
  105. </div>
  106. <RouterView />
  107. <!-- 固定的二维码和游戏 -->
  108. <div class="rightNav">
  109. <ul
  110. class="rightIco"
  111. data-aria-viewport-area
  112. aria-description="You've reached the pop-up window section, which has one search field, one URL and one image. Please use the tab key to go through the information."
  113. >
  114. <li
  115. class="searchLi"
  116. v-if="$route.name !== 'Search'"
  117. aria-description="You've reached the search field, please use the tab key to browse the content."
  118. >
  119. <div class="searchHover">
  120. <div class="ll" @click="handleSearch(searchTxt2)">
  121. <img src="@/assets/images/LayoutSearch2.jpg" alt="" />
  122. </div>
  123. <div class="rr">
  124. <input
  125. type="text"
  126. placeholder="search"
  127. v-model="searchTxt2"
  128. :aria-description="searchTxt2 || 'search'"
  129. @keyup.enter="handleSearch(searchTxt2)"
  130. />
  131. </div>
  132. </div>
  133. <svg-icon name="search2" color="var(--van-white)" size="32" />
  134. </li>
  135. <li title="game">
  136. <a
  137. href="/game/index.html#/?lang=en-us"
  138. target="_blank"
  139. tabindex="0"
  140. aria-description="shadow art game"
  141. >
  142. <svg-icon name="game" color="var(--van-white)" size="50" />
  143. </a>
  144. </li>
  145. <li>
  146. <svg-icon name="code" color="var(--van-white)" size="50" />
  147. <div>
  148. <img src="@/assets/images/index_ewm1.png" alt="" />
  149. <img
  150. src="@/assets/images/index_ewm.jpg"
  151. aria-description="Official microblog and wechat QR code"
  152. />
  153. </div>
  154. </li>
  155. </ul>
  156. </div>
  157. <!-- 底部固定栏 -->
  158. <div
  159. class="footer"
  160. data-aria-viewport-area
  161. aria-label="Footer"
  162. aria-description="You've reached footer section at the bottom of the website. This section contains four URLs. To browse the content, please use the tab key."
  163. >
  164. <div>
  165. <template v-for="item in footerData" :key="item.name">
  166. |
  167. <RouterLink
  168. class="router-link"
  169. replace
  170. :to="item.path"
  171. v-html="item.name"
  172. :aria-description="item.name"
  173. />
  174. </template>
  175. </div>
  176. <p>
  177. Capital Museum. China 16 Fuxingmenwai Street, Xicheng District,
  178. Beijing 100045, P.R.China.
  179. </p>
  180. </div>
  181. </div>
  182. </div>
  183. </template>
  184. <script setup lang="ts">
  185. import { ref, watch } from "vue";
  186. import { useRoute, useRouter, type RouteLocationNamedRaw } from "vue-router";
  187. import Accessibility from "@/components/Accessibility/index.vue";
  188. import { useTheme, THEME_COLOR } from "@/components/Accessibility/hooks";
  189. import { topData, footerData } from "./data";
  190. import Logo from "@/assets/images/logo.png";
  191. import Logo2 from "@/assets/images/logo2.png";
  192. const THEME_MAP: Record<THEME_COLOR, string> = {
  193. [THEME_COLOR.DEFAULT]: "",
  194. [THEME_COLOR.WHITE]: "white",
  195. [THEME_COLOR.BLUE]: "blue",
  196. [THEME_COLOR.YELLOW]: "yellow",
  197. [THEME_COLOR.BLACK]: "black",
  198. };
  199. const themeIdx = useTheme();
  200. const route = useRoute();
  201. const router = useRouter();
  202. /** 是否开启爱心模式 */
  203. const loveSwitch = ref(false);
  204. const accessibility = ref();
  205. const searchTxt = ref("");
  206. const searchTxt2 = ref("");
  207. watch(loveSwitch, (v) => {
  208. if (v) {
  209. accessibility.value?.requestToShowMenu();
  210. } else {
  211. accessibility.value?.requestToHideMenu();
  212. }
  213. });
  214. watch(
  215. route,
  216. () => {
  217. searchTxt.value = "";
  218. },
  219. {
  220. immediate: true,
  221. }
  222. );
  223. const handleSearch = (txt: string) => {
  224. router.push({
  225. name: "Search",
  226. query: { keyword: encodeURIComponent(txt) },
  227. });
  228. searchTxt2.value = "";
  229. searchTxt.value = "";
  230. };
  231. </script>
  232. <style lang="scss">
  233. .layout {
  234. --van-primary-color: #ca000a;
  235. --topnav-bg-color: rgba(0, 0, 0, 0.8);
  236. --primary-hover-bg: rgba(204, 0, 3, 0.8);
  237. --black-text-color: black;
  238. --black2-text-color: #101010;
  239. --gray-text-color: #666;
  240. --gray2-text-color: #a6a6a6;
  241. --white-bg: white;
  242. --white-text-color: white;
  243. --page-bg-color: #f1f1f1;
  244. font-family: "SourceHanSans-Regular";
  245. min-width: 1200px;
  246. background-color: var(--page-bg-color);
  247. &.white {
  248. --topnav-bg-color: white;
  249. --van-white: black;
  250. --primary-hover-bg: white;
  251. --black-text-color: black;
  252. --black2-text-color: black;
  253. --gray-text-color: #666;
  254. --gray2-text-color: #a6a6a6;
  255. --white-bg: white;
  256. --white-text-color: black;
  257. --page-bg-color: white;
  258. }
  259. &.blue {
  260. --topnav-bg-color: #00f;
  261. --van-white: #ff0;
  262. --primary-hover-bg: #00f;
  263. --black-text-color: #ff0;
  264. --black2-text-color: #ff0;
  265. --gray-text-color: #ff0;
  266. --gray2-text-color: #ff0;
  267. --white-bg: #00f;
  268. --white-text-color: #ff0;
  269. --page-bg-color: #00f;
  270. }
  271. &.yellow {
  272. --topnav-bg-color: #ff0;
  273. --van-white: black;
  274. --primary-hover-bg: #ff0;
  275. --black-text-color: black;
  276. --black2-text-color: black;
  277. --gray-text-color: black;
  278. --gray2-text-color: black;
  279. --white-bg: #ff0;
  280. --white-text-color: black;
  281. --page-bg-color: #ff0;
  282. }
  283. &.black {
  284. --topnav-bg-color: black;
  285. --van-white: #ff0;
  286. --primary-hover-bg: black;
  287. --black-text-color: #ff0;
  288. --black2-text-color: #ff0;
  289. --gray-text-color: #ff0;
  290. --gray2-text-color: #ff0;
  291. --white-bg: black;
  292. --white-text-color: #ff0;
  293. --page-bg-color: black;
  294. }
  295. &-main {
  296. position: relative;
  297. min-height: 100vh;
  298. padding-bottom: 45px;
  299. }
  300. }
  301. .topnav {
  302. position: absolute;
  303. top: 0;
  304. left: 0;
  305. right: 0;
  306. display: flex;
  307. align-items: center;
  308. justify-content: flex-end;
  309. padding: 0 40px 0 5px;
  310. height: inherit;
  311. background: var(--topnav-bg-color);
  312. z-index: 2;
  313. &-wrap {
  314. position: relative;
  315. height: 60px;
  316. }
  317. &-container {
  318. display: flex;
  319. align-items: center;
  320. flex: 1;
  321. max-width: calc(1300px + 240px + 30px);
  322. height: inherit;
  323. }
  324. &-list {
  325. flex: 1;
  326. display: flex;
  327. justify-content: space-between;
  328. padding: 0 70px;
  329. height: inherit;
  330. line-height: 60px;
  331. font-size: 14px;
  332. color: var(--van-white);
  333. > li {
  334. position: relative;
  335. cursor: pointer;
  336. user-select: none;
  337. > span {
  338. white-space: nowrap;
  339. }
  340. &:hover,
  341. &:focus-within {
  342. & > span {
  343. border-bottom: 2px solid var(--van-primary-color);
  344. }
  345. .main_nav_sub {
  346. display: block;
  347. }
  348. }
  349. &.active {
  350. & > span {
  351. border-bottom: 2px solid var(--van-primary-color);
  352. }
  353. }
  354. .main_nav_sub {
  355. display: none;
  356. position: absolute;
  357. z-index: 1;
  358. span {
  359. border-left: 2px solid #660005;
  360. font-size: 14px;
  361. color: inherit;
  362. height: 40px;
  363. line-height: 40px;
  364. background-color: var(--topnav-bg-color);
  365. white-space: nowrap;
  366. display: block;
  367. padding: 0 20px 0 10px;
  368. &:hover {
  369. background-color: var(--primary-hover-bg);
  370. border-left: 2px solid var(--van-primary-color);
  371. }
  372. }
  373. .active2 {
  374. background-color: var(--primary-hover-bg);
  375. border-left: 2px solid var(--van-primary-color);
  376. }
  377. }
  378. }
  379. }
  380. .language {
  381. width: 73px;
  382. background: url("@/assets/images/dh1.png") no-repeat 0 18px;
  383. & > a {
  384. color: #fff;
  385. text-decoration: none;
  386. display: inline-block;
  387. margin-left: 40px;
  388. padding-right: 5px;
  389. &:hover {
  390. border-bottom: 2px solid var(--van-primary-color);
  391. }
  392. }
  393. }
  394. .love {
  395. --van-switch-width: 40px;
  396. --van-switch-height: 20px;
  397. --van-switch-node-size: calc(var(--van-switch-height) - 4px);
  398. display: flex;
  399. align-items: center;
  400. gap: 8px;
  401. }
  402. .search {
  403. margin-left: 40px;
  404. position: relative;
  405. width: 240px;
  406. height: 30px;
  407. .svg-icon {
  408. position: absolute;
  409. top: 50%;
  410. right: 8px;
  411. transform: translateY(-50%);
  412. }
  413. input {
  414. font-size: 14px;
  415. background-color: #fff;
  416. border: 1px solid #dcdfe6;
  417. box-sizing: border-box;
  418. color: #606266;
  419. display: inline-block;
  420. outline: 0;
  421. padding: 0 30px 0 15px;
  422. transition: border-color 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);
  423. width: 100%;
  424. height: 30px;
  425. border-radius: 15px;
  426. line-height: 30px;
  427. &:focus {
  428. border-color: var(--van-primary-color);
  429. }
  430. &::placeholder {
  431. color: black;
  432. }
  433. }
  434. }
  435. }
  436. .footer {
  437. position: absolute;
  438. left: 0;
  439. right: 0;
  440. bottom: 0;
  441. display: flex;
  442. justify-content: space-between;
  443. padding: 0 100px;
  444. font-size: 14px;
  445. color: var(--van-white);
  446. line-height: 45px;
  447. background: var(--topnav-bg-color);
  448. .router-link {
  449. color: inherit;
  450. margin: 0 10px;
  451. }
  452. }
  453. .rightNav {
  454. position: fixed;
  455. top: 60%;
  456. right: 0;
  457. height: 164px;
  458. width: 60px;
  459. z-index: var(--el-index-popper);
  460. .rightIco {
  461. width: 100%;
  462. height: 100%;
  463. & > li {
  464. background: var(--topnav-bg-color);
  465. text-align: center;
  466. width: 60px;
  467. padding: 10px 0;
  468. position: relative;
  469. cursor: pointer;
  470. & > div {
  471. display: none;
  472. width: 252px;
  473. position: absolute;
  474. top: 0;
  475. right: 0;
  476. & > img {
  477. float: left;
  478. }
  479. }
  480. &:hover,
  481. &:focus-within {
  482. background: var(--primary-hover-bg);
  483. & > div {
  484. display: block;
  485. }
  486. }
  487. }
  488. .searchLi {
  489. padding-top: 18px;
  490. position: relative;
  491. .searchHover {
  492. position: absolute;
  493. top: 0;
  494. right: 0;
  495. width: 300px;
  496. height: 60px;
  497. display: flex !important;
  498. opacity: 0;
  499. pointer-events: none;
  500. .ll {
  501. width: 60px;
  502. height: 60px;
  503. display: flex;
  504. justify-content: center;
  505. align-items: center;
  506. background-color: #fff;
  507. border: 1px solid #a3a3a3;
  508. }
  509. .rr {
  510. width: 240px;
  511. background-color: var(--van-primary-color);
  512. padding: 8px;
  513. input {
  514. padding: 0 5px;
  515. width: 200px;
  516. height: 38px;
  517. line-height: 44px;
  518. &:focus {
  519. border-color: #000 !important;
  520. outline: 2px solid #000 !important;
  521. }
  522. }
  523. }
  524. }
  525. &:hover,
  526. &:focus-within {
  527. .searchHover {
  528. opacity: 1;
  529. pointer-events: auto;
  530. }
  531. }
  532. }
  533. }
  534. }
  535. @media screen and (max-width: 1430px) {
  536. .topnav {
  537. padding-right: 5px;
  538. &-list {
  539. padding: 0 20px;
  540. font-size: 12px;
  541. }
  542. .search {
  543. margin-left: 0;
  544. }
  545. }
  546. }
  547. </style>