Home.vue 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907
  1. <script setup>
  2. import { ref, reactive, watch, onMounted } from "vue";
  3. import { useMainStore } from "@/stores/store";
  4. import { useI18n } from "vue-i18n";
  5. import axios from "axios";
  6. import moment from "moment";
  7. import Map from "@/components/Map.vue";
  8. import Navbar from "@/components/Navbar.vue";
  9. import HomeList from "@/components/HomeList.vue";
  10. import TermsList from "@/components/TermsList.vue";
  11. import CourseCard from "@/components/CourseCard.vue";
  12. import CoursesTutorial from "@/components/CoursesTutorial.vue";
  13. import CraftsArticle from "@/components/CraftsArticle.vue";
  14. const store = useMainStore();
  15. const { t } = useI18n();
  16. let loading = ref(true);
  17. onMounted(() => {
  18. setTimeout(() => {
  19. loading.value = false;
  20. }, 300);
  21. });
  22. let pageNum = ref(1); // 頁數(預設第一頁)
  23. let pageAmount = ref(4); // 每頁顯示筆數
  24. let totalPages = ref(1); // 總頁數
  25. // 切換分頁
  26. watch(pageNum, () => {
  27. getClass();
  28. });
  29. let classes = reactive({
  30. data: [],
  31. });
  32. let assignState = ref(false);
  33. let assignLocationId = ref(null);
  34. async function getClass() {
  35. let url = `https://cmm.ai:8088/api/get_class_name?is_check=1&page_num=${pageNum.value}&page_amount=${pageAmount.value}`;
  36. let assignUrl = `https://cmm.ai:8088/api/get_class_name?is_check=1&page_num=${pageNum.value}&page_amount=${pageAmount.value}&location_id=${assignLocationId.value}`;
  37. try {
  38. const response = await axios.get(assignState.value ? assignUrl : url);
  39. totalPages.value = store.getTotalPages(response.data.total_num, 4);
  40. classes.data = response.data.classes;
  41. } catch (error) {
  42. console.error(error);
  43. }
  44. }
  45. getClass();
  46. // 取得特定據點課程總筆數
  47. const getClassList = async (locationId) => {
  48. assignState.value = true;
  49. assignLocationId.value = locationId;
  50. try {
  51. const response = await axios.get(
  52. `https://cmm.ai:8088/api/get_class_name?location_id=${locationId}`
  53. );
  54. getClass();
  55. pageNum.value = 1;
  56. totalPages.value = store.getTotalPages(response.data.classes.length, 4);
  57. } catch (error) {
  58. console.log("error", error);
  59. }
  60. };
  61. let recommend = reactive({
  62. list: [],
  63. });
  64. // 推薦課程
  65. (async () => {
  66. try {
  67. const response = await axios.get(
  68. "https://cmm.ai:8088/api/get_class_name?recommend=1"
  69. );
  70. console.log("推薦課程", response);
  71. recommend.list = response.data.classes;
  72. console.log(" recommend.list", recommend.list);
  73. } catch (error) {
  74. console.error(error);
  75. }
  76. })();
  77. let panel = ref([]);
  78. const tagList = reactive([
  79. {
  80. title: "crafts.title_1",
  81. url: "/crafts#articleList",
  82. },
  83. {
  84. title: "crafts.title_2",
  85. url: "/crafts#readList",
  86. },
  87. {
  88. title: "crafts.title_3",
  89. url: "/crafts#bookList",
  90. },
  91. {
  92. title: "crafts.title_4",
  93. url: "/crafts#journal",
  94. },
  95. {
  96. title: "crafts.title_5",
  97. url: "/crafts#thesisGrant",
  98. },
  99. ]);
  100. let news = reactive({
  101. list: [],
  102. });
  103. // 重要訊息
  104. (async () => {
  105. // 取得最新兩篇
  106. try {
  107. const response = await axios.get(
  108. "https://cmm.ai:8088/api/get_news?page_num=1&page_amount=2"
  109. );
  110. news.list = response.data.news;
  111. console.log("重要訊息", news.list);
  112. } catch (error) {
  113. console.error(error);
  114. }
  115. })();
  116. let assignTag = ref("news");
  117. // watch(assignTag, (val) => {
  118. // if (val === "all") {
  119. // isInternal.value = false;
  120. // } else {
  121. // isInternal.value = true;
  122. // }
  123. // pageNum.value = 1;
  124. // getClass();
  125. // });
  126. function selectTag(btn) {
  127. if (btn === "news") {
  128. assignTag.value = "news";
  129. } else {
  130. assignTag.value = "exhibit";
  131. }
  132. }
  133. // 使用 ref 定義底部彈出視窗的狀態
  134. // const isBottomSheetOpen = ref(false);
  135. // 打開底部彈出視窗
  136. // const openBottomSheet = () => {
  137. // isBottomSheetOpen.value = !isBottomSheetOpen.value;
  138. // };
  139. // 按住向上滑動的手勢處理函數
  140. // const onSlideUpDown = (event) => {
  141. // console.log("onSlideUpDown");
  142. // const touch = event.changedTouches[0];
  143. // const startY = touch.clientY;
  144. // const onTouchMove = (event) => {
  145. // console.log("onTouchMove");
  146. // const touchMove = event.changedTouches[0];
  147. // const currentY = touchMove.clientY;
  148. // const deltaY = startY - currentY;
  149. // 滑動超過一定距離(如 100px)打開底部彈出視窗
  150. // if (deltaY > 50) {
  151. // console.log("向上滑動");
  152. // isBottomSheetOpen.value = true;
  153. // }
  154. // 向下滑動超過一定距離(如 -100px)關閉底部彈出視窗
  155. // if (deltaY < -100) {
  156. // console.log("向下滑動");
  157. // isBottomSheetOpen.value = false;
  158. // }
  159. // };
  160. // document.addEventListener("touchmove", onTouchMove);
  161. // };
  162. </script>
  163. <template>
  164. <Transition>
  165. <div class="loading-item" v-if="loading">
  166. <v-progress-circular
  167. color="grey-lighten-4"
  168. indeterminate
  169. ></v-progress-circular>
  170. </div>
  171. </Transition>
  172. <div class="banner">
  173. <img src="@/assets/img/home/banner.webp" alt="" class="cover" />
  174. <img src="@/assets/img/home/logo.png" alt="" class="logo" />
  175. </div>
  176. <Navbar />
  177. <v-container class="px-md-0 pb-16 mb-16">
  178. <section class="text-center intro">
  179. <h2 class="title">{{ t("home.title_1") }}</h2>
  180. <p class="my-10">
  181. {{ t("home.content") }}
  182. </p>
  183. <!-- <p class="my-10">
  184. 以佈局具國際視野之工藝學習共享平台為目標,藉由「工藝學校」的主體概念,推動臺灣工藝學校全球學習平台,以共享、友善、全人、全民的終身工藝手作平台進行人才、課程、知識、教材之工藝資源嫁接媒合與內容設計,以在地、就近、線上、線下等多元方式提供不同型態之學習體驗內容及選擇。
  185. </p>
  186. <p>
  187. With the goal of laying out a craft learning and sharing platform with
  188. an international perspective, through the main concept of "craft
  189. school", we promote the global learning platform of International Craft
  190. Learning Platform co-ops, and use a lifelong craft platform run on the
  191. values of sharing, friendliness, and holisticness to design and
  192. integrate craft resources such as talents, courses, knowledge and
  193. teaching materials, and provide different types of learning experiences
  194. in local ways, both online and offline.
  195. </p> -->
  196. </section>
  197. <v-carousel
  198. cycle
  199. height="400"
  200. hide-delimiters
  201. hide-delimiter-background
  202. show-arrows="hover"
  203. >
  204. <v-carousel-item>
  205. <div class="d-flex h-100 align-center">
  206. <img src="@/assets/img/home/carousel-01.jpg" alt="" class="w-100" />
  207. </div>
  208. </v-carousel-item>
  209. </v-carousel>
  210. <div class="news-content">
  211. <div class="d-flex tab-btn mb-16">
  212. <v-btn
  213. variant="text"
  214. @click="selectTag('news')"
  215. :class="{ active: assignTag === 'news' }"
  216. >
  217. 重要訊息
  218. </v-btn>
  219. <v-btn
  220. variant="text"
  221. @click="selectTag('exhibit')"
  222. :class="{ active: assignTag === 'exhibit' }"
  223. >
  224. 當期展覽
  225. </v-btn>
  226. </div>
  227. <div class="d-flex justify-end">
  228. <router-link to="/news">觀看更多訊息 >></router-link>
  229. </div>
  230. <ul>
  231. <li v-for="(item, index) in news.list" :key="index" class="mb-16 list">
  232. <HomeList :data="item" />
  233. <!-- <section class="d-flex">
  234. <p class="category mb-5">
  235. <span></span>
  236. {{ item.category }}
  237. </p>
  238. <p class="ms-5">
  239. {{ moment(`${item.create_time}`).format("YYYY-MM-DD") }}
  240. </p>
  241. </section>
  242. <v-card
  243. variant="outlined"
  244. class="d-flex flex-md-row flex-column align-center pa-5"
  245. >
  246. <v-row class="align-center">
  247. <v-col cols="12">
  248. <router-link :to="`/news/${item.news_id}`" class="cover-img">
  249. <section class="d-flex flex-column pa-3">
  250. <h3>{{ item.title }}</h3>
  251. <p v-html="item.content"></p>
  252. </section>
  253. </router-link>
  254. </v-col>
  255. </v-row>
  256. </v-card> -->
  257. </li>
  258. </ul>
  259. </div>
  260. <h2 class="my-10 title">{{ t("home.title_2") }}</h2>
  261. <v-row>
  262. <v-col cols="6" md="4">
  263. <router-link to="/" class="img-info">
  264. <img src="@/assets/img/home/首頁元素-12.png" alt="" />
  265. <section>
  266. <p>{{ t("college_group_1") }}</p>
  267. </section>
  268. </router-link>
  269. </v-col>
  270. <v-col cols="6" md="4">
  271. <router-link to="/college-group/craft" class="img-info">
  272. <img src="@/assets/img/home/首頁元素-11.png" alt="" />
  273. <section>
  274. <p>{{ t("college_group_2") }}</p>
  275. </section>
  276. </router-link>
  277. </v-col>
  278. <v-col cols="6" md="4">
  279. <router-link to="/college-group/future" class="img-info">
  280. <img src="@/assets/img/home/首頁元素-06.png" alt="" />
  281. <section>
  282. <p>{{ t("college_group_3") }}</p>
  283. </section>
  284. </router-link>
  285. </v-col>
  286. <v-col cols="6" md="4">
  287. <router-link to="/college-group/cross" class="img-info">
  288. <img src="@/assets/img/home/首頁元素-09.png" alt="" />
  289. <section>
  290. <p>{{ t("college_group_4") }}</p>
  291. </section>
  292. </router-link>
  293. </v-col>
  294. <v-col cols="6" md="4">
  295. <router-link to="/college-group/craft-for-all" class="img-info">
  296. <img src="@/assets/img/home/臺灣綠工藝希望工程.png" alt="" />
  297. <section>
  298. <p>{{ t("college_group_5") }}</p>
  299. </section>
  300. </router-link>
  301. </v-col>
  302. <v-col cols="6" md="4">
  303. <router-link to="/college-group/life" class="img-info">
  304. <img src="@/assets/img/home/首頁元素-07.png" alt="" />
  305. <section>
  306. <p>{{ t("college_group_6") }}</p>
  307. </section>
  308. </router-link>
  309. </v-col>
  310. </v-row>
  311. <div class="map-block">
  312. <h3 class="mb-10 title">{{ t("home.title_3") }}</h3>
  313. <div class="v-row">
  314. <v-col md="8" cols="12">
  315. <div class="map">
  316. <Map @locationId="getClassList" />
  317. </div>
  318. </v-col>
  319. <v-col md="4" cols="12">
  320. <v-list lines="three" class="list pa-0">
  321. <v-list-item v-for="item in classes.data" :key="item.id">
  322. <div class="d-flex align-center">
  323. <router-link
  324. :to="`/course-detail/${item.class_name_id}`"
  325. class="link"
  326. >
  327. <v-img
  328. :lazy-src="
  329. item.is_inner === 0
  330. ? item.cover_img
  331. : item.special_class_list_name === 'one_day_class'
  332. ? store.getImageUrl('default.png')
  333. : `https://ntcri.org/${item.cover_img}`
  334. "
  335. cover
  336. :src="
  337. item.is_inner === 0
  338. ? item.cover_img
  339. : item.special_class_list_name === 'one_day_class'
  340. ? store.getImageUrl('default.png')
  341. : `https://ntcri.org/${item.cover_img}`
  342. "
  343. >
  344. <template v-slot:placeholder>
  345. <div
  346. class="d-flex align-center justify-center fill-height"
  347. >
  348. <v-progress-circular
  349. color="grey-lighten-4"
  350. indeterminate
  351. ></v-progress-circular>
  352. </div>
  353. </template>
  354. </v-img>
  355. </router-link>
  356. <section>
  357. <h2>{{ item.name }}</h2>
  358. <div class="d-flex align-start">
  359. <v-icon
  360. color="primary"
  361. icon="mdi-domain"
  362. class="me-2"
  363. ></v-icon>
  364. <p>{{ item.organizer }}</p>
  365. </div>
  366. <div class="d-flex align-start">
  367. <v-icon
  368. color="primary"
  369. icon="mdi-map-marker"
  370. class="me-2 pt-1"
  371. ></v-icon>
  372. <p>{{ item.location_name }}</p>
  373. </div>
  374. </section>
  375. </div>
  376. </v-list-item>
  377. </v-list>
  378. <v-pagination
  379. v-model="pageNum"
  380. :length="totalPages"
  381. class="my-4"
  382. rounded="circle"
  383. ></v-pagination>
  384. </v-col>
  385. </div>
  386. <!-- <div class="map">
  387. <Map @locationId="getClassList" />
  388. </div> -->
  389. </div>
  390. <h2 class="mb-10 title">{{ t("home.title_4") }}</h2>
  391. <v-row>
  392. <v-col
  393. cols="12"
  394. sm="6"
  395. lg="4"
  396. v-for="(item, index) in recommend.list"
  397. :key="index"
  398. class="pa-5"
  399. >
  400. <CourseCard :data="item" />
  401. </v-col>
  402. <v-col cols="12">
  403. <router-link to="/course-list" class="course-link">
  404. <img src="@/assets/img/course/探索課程素材-15.png" alt="" />
  405. <p>{{ t("see_more") }}</p>
  406. </router-link>
  407. </v-col>
  408. </v-row>
  409. <!-- 手機版底部視窗 -->
  410. <!-- <div
  411. class="bottom-sheet"
  412. @touchstart.prevent="onSlideUpDown"
  413. :class="{ show: isBottomSheetOpen }"
  414. >
  415. <div class="content">
  416. <span></span>
  417. <div class="list">
  418. <h2>Bottom Sheet Content</h2>
  419. </div>
  420. </div>
  421. </div> -->
  422. </v-container>
  423. <v-container fluid class="pa-0 pt-sm-16 tutorial-block">
  424. <h2 class="mb-10 title">{{ t("tutorial.title") }}</h2>
  425. <CoursesTutorial />
  426. </v-container>
  427. <v-container class="px-md-0 my-16">
  428. <h2 class="mb-10 title">{{ t("home.title_6") }}</h2>
  429. <v-expansion-panels v-model="panel" multiple>
  430. <v-expansion-panel elevation="0">
  431. <v-expansion-panel-title>{{
  432. t("home.faq.q_1")
  433. }}</v-expansion-panel-title>
  434. <v-expansion-panel-text>
  435. <ul>
  436. <li>
  437. <h4><span></span> {{ t("home.faq.a_1_1") }}</h4>
  438. <p>
  439. {{ t("home.faq.a_1_2") }}
  440. </p>
  441. </li>
  442. <li>
  443. <h4><span></span> {{ t("home.faq.a_2_1") }}</h4>
  444. <p>
  445. {{ t("home.faq.a_2_2") }}
  446. </p>
  447. </li>
  448. <li>
  449. <h4><span></span> {{ t("home.faq.a_3_1") }}</h4>
  450. <p>
  451. {{ t("home.faq.a_3_2") }}
  452. </p>
  453. </li>
  454. <li>
  455. <h4><span></span> {{ t("home.faq.a_4_1") }}</h4>
  456. <p>
  457. {{ t("home.faq.a_4_2") }}
  458. </p>
  459. </li>
  460. </ul>
  461. </v-expansion-panel-text>
  462. </v-expansion-panel>
  463. <v-expansion-panel elevation="0">
  464. <v-expansion-panel-title>
  465. {{ t("terms.terms_of_service") }}</v-expansion-panel-title
  466. >
  467. <v-expansion-panel-text>
  468. <TermsList />
  469. </v-expansion-panel-text>
  470. </v-expansion-panel>
  471. <v-expansion-panel elevation="0">
  472. <v-expansion-panel-title>{{
  473. t("home.faq.q_2")
  474. }}</v-expansion-panel-title>
  475. <v-expansion-panel-text>
  476. <p v-html="$t('home.faq.a_2')"></p>
  477. </v-expansion-panel-text>
  478. </v-expansion-panel>
  479. <v-expansion-panel elevation="0">
  480. <v-expansion-panel-title>{{
  481. t("home.faq.q_3")
  482. }}</v-expansion-panel-title>
  483. <v-expansion-panel-text>
  484. {{ t("home.faq.a_3") }}
  485. </v-expansion-panel-text>
  486. </v-expansion-panel>
  487. <v-expansion-panel elevation="0">
  488. <v-expansion-panel-title>{{
  489. t("home.faq.q_4")
  490. }}</v-expansion-panel-title>
  491. <v-expansion-panel-text>
  492. {{ t("home.faq.a_4") }}
  493. </v-expansion-panel-text>
  494. </v-expansion-panel>
  495. <v-expansion-panel elevation="0">
  496. <v-expansion-panel-title>{{
  497. t("home.faq.q_5")
  498. }}</v-expansion-panel-title>
  499. <v-expansion-panel-text>
  500. {{ t("home.faq.a_5") }}
  501. </v-expansion-panel-text>
  502. </v-expansion-panel>
  503. </v-expansion-panels>
  504. <h2 class="mb-10 mt-16 title">{{ t("crafts.title") }}</h2>
  505. <v-row class="px-5 px-sm-10 mt-16 mb-10 tag-btn">
  506. <v-col
  507. v-for="(item, index) in tagList"
  508. :key="index"
  509. :cols="index + 1 === tagList.length ? '12' : '6'"
  510. md=""
  511. >
  512. <a :href="item.url" target="_blank" class="py-3 py-lg-6 item">
  513. <!-- 網址 -->
  514. {{ t(`${item.title}`) }}
  515. </a>
  516. </v-col>
  517. </v-row>
  518. <CraftsArticle />
  519. <router-link to="/crafts" class="crafts-link">
  520. <img src="@/assets/img/course/探索課程素材-15.png" alt="" />
  521. <p>{{ t("crafts.see_more") }}</p>
  522. </router-link>
  523. <div class="mt-16">
  524. <img
  525. class="d-none d-md-block"
  526. src="@/assets/img/course/banner.png"
  527. alt=""
  528. />
  529. <img
  530. class="d-block d-md-none"
  531. src="@/assets/img/course/banner-mb.png"
  532. alt=""
  533. />
  534. </div>
  535. </v-container>
  536. </template>
  537. <style lang="scss" scoped>
  538. .banner {
  539. display: flex;
  540. align-items: center;
  541. justify-content: center;
  542. position: relative;
  543. .cover {
  544. width: 100vw;
  545. height: 100vh;
  546. object-fit: cover;
  547. }
  548. .logo {
  549. width: 800px;
  550. position: absolute;
  551. z-index: 10;
  552. }
  553. }
  554. .intro {
  555. margin: 120px 0 100px;
  556. p {
  557. line-height: 32px;
  558. }
  559. }
  560. .title {
  561. font-size: 26px;
  562. font-weight: 400;
  563. letter-spacing: 2px;
  564. text-align: center;
  565. }
  566. .navbar {
  567. margin-bottom: 0;
  568. }
  569. .img-info {
  570. display: block;
  571. position: relative;
  572. section {
  573. width: 100%;
  574. height: 100%;
  575. position: absolute;
  576. top: 0;
  577. display: flex;
  578. align-items: center;
  579. justify-content: center;
  580. background: rgba(167, 193, 204, 0.7);
  581. cursor: pointer;
  582. opacity: 0;
  583. transition: all 0.5s;
  584. &:hover {
  585. opacity: 1;
  586. }
  587. p {
  588. color: #fff;
  589. font-size: 20px;
  590. letter-spacing: 1px;
  591. }
  592. }
  593. }
  594. .news-content {
  595. margin: 100px auto;
  596. }
  597. .map-block {
  598. margin: 100px auto;
  599. .map {
  600. height: 100%;
  601. min-height: 100vh;
  602. }
  603. .list {
  604. .link {
  605. width: 40%;
  606. margin-right: 20px;
  607. border-radius: 5px;
  608. overflow: hidden;
  609. @media (max-width: 960px) {
  610. width: auto;
  611. }
  612. .v-img {
  613. width: 200px;
  614. height: 150px;
  615. margin-right: 20px;
  616. border-radius: 5px;
  617. box-shadow: 2px 2px 4px #aaaaaa;
  618. transition: all 0.3s;
  619. object-fit: cover;
  620. @media (max-width: 960px) {
  621. width: 250px;
  622. height: 170px;
  623. margin-right: 0;
  624. }
  625. &:hover {
  626. transform: scale(1.1);
  627. }
  628. }
  629. }
  630. section {
  631. width: 60%;
  632. h2 {
  633. margin-bottom: 10px;
  634. font-size: 16px;
  635. font-weight: 500;
  636. }
  637. p {
  638. font-size: 14px;
  639. font-weight: 400;
  640. }
  641. h2,
  642. p {
  643. line-height: 26px;
  644. letter-spacing: 1px;
  645. // 超過兩行則省略
  646. overflow: hidden;
  647. text-overflow: ellipsis;
  648. display: -webkit-box;
  649. -webkit-line-clamp: 2;
  650. -webkit-box-orient: vertical;
  651. line-break: after-white-space;
  652. }
  653. }
  654. .v-list-item {
  655. height: 215px;
  656. padding: 20px 0;
  657. border-bottom: 1px solid #cccccc;
  658. &:last-child {
  659. border-bottom: none;
  660. }
  661. .v-list-item__content {
  662. overflow: initial !important;
  663. }
  664. }
  665. }
  666. }
  667. .course-link {
  668. margin-top: 15px;
  669. color: #000;
  670. background-color: var(--sub-color);
  671. }
  672. .crafts-link {
  673. margin: 100px 0;
  674. color: #fff;
  675. background-color: var(--purple);
  676. img {
  677. filter: invert(88%) sepia(100%) saturate(0%) hue-rotate(151deg)
  678. brightness(103%) contrast(103%);
  679. }
  680. }
  681. .crafts-link,
  682. .course-link {
  683. padding: 15px;
  684. display: flex;
  685. align-items: center;
  686. justify-content: center;
  687. border-radius: 10px;
  688. box-shadow: 2px 2px 10px #aaaaaa;
  689. &:hover {
  690. img {
  691. transform: rotateZ(10deg);
  692. }
  693. }
  694. img {
  695. max-width: 85px;
  696. padding-right: 20px;
  697. transition: all 0.3s;
  698. }
  699. p {
  700. font-size: 20px;
  701. letter-spacing: 2px;
  702. }
  703. }
  704. .tutorial-block {
  705. max-width: 100% !important;
  706. }
  707. .loading-item {
  708. position: sticky;
  709. top: 0;
  710. left: 0;
  711. right: 0;
  712. height: 100vh;
  713. z-index: 3000;
  714. display: flex;
  715. align-items: center;
  716. justify-content: center;
  717. background: #fff;
  718. }
  719. // Vuetify Expansion 樣式
  720. .v-expansion-panel {
  721. margin-bottom: 30px;
  722. line-height: 30px;
  723. border-radius: 10px !important;
  724. li:first-child {
  725. h4 {
  726. margin-top: 0;
  727. }
  728. }
  729. h4 {
  730. display: flex;
  731. align-items: center;
  732. margin-top: 20px;
  733. font-size: 18px;
  734. font-weight: 500;
  735. span {
  736. display: block;
  737. width: 8px;
  738. height: 8px;
  739. margin-top: 5px;
  740. margin-right: 10px;
  741. border-radius: 10px;
  742. background-color: var(--blue);
  743. }
  744. }
  745. }
  746. .v-expansion-panel-title {
  747. padding: 20px 30px;
  748. font-size: 16px;
  749. line-height: 26px;
  750. letter-spacing: 1px;
  751. border: 1px solid var(--blue);
  752. }
  753. .v-expansion-panel-text {
  754. padding-top: 8px;
  755. }
  756. .v-expansion-panel-title__overlay {
  757. opacity: 0 !important;
  758. }
  759. .v-expansion-panels:not(.v-expansion-panels--variant-accordion)
  760. > :first-child:not(:last-child):not(.v-expansion-panel--active):not(
  761. .v-expansion-panel--before-active
  762. ),
  763. .v-expansion-panels:not(.v-expansion-panels--variant-accordion)
  764. > :last-child:not(:first-child):not(.v-expansion-panel--active):not(
  765. .v-expansion-panel--after-active
  766. ),
  767. .v-expansion-panels:not(.v-expansion-panels--variant-accordion)
  768. > :not(:first-child):not(:last-child):not(.v-expansion-panel--active):not(
  769. .v-expansion-panel--after-active
  770. ),
  771. .v-expansion-panels:not(.v-expansion-panels--variant-accordion)
  772. > :not(:first-child):not(:last-child):not(.v-expansion-panel--active):not(
  773. .v-expansion-panel--before-active
  774. ),
  775. .v-expansion-panel--active > .v-expansion-panel-title {
  776. border-top-left-radius: 10px !important;
  777. border-top-right-radius: 10px !important;
  778. border-bottom-left-radius: 10px !important;
  779. border-bottom-right-radius: 10px !important;
  780. }
  781. .v-expansion-panel:not(:first-child)::after {
  782. border-top-style: none;
  783. }
  784. .v-expansion-panel-title--active:hover > .v-expansion-panel-title__overlay,
  785. .v-expansion-panel-title[aria-haspopup="menu"][aria-expanded="true"]:hover
  786. > .v-expansion-panel-title__overlay {
  787. opacity: 0;
  788. }
  789. /* 底部彈出視窗的樣式 */
  790. .bottom-sheet {
  791. display: none;
  792. // display: flex;
  793. justify-content: center;
  794. align-items: center;
  795. position: fixed;
  796. bottom: 40px;
  797. left: 0;
  798. width: 100%;
  799. height: 300px; /* 設置底部彈出視窗的高度 */
  800. z-index: 1000;
  801. background-color: #fff;
  802. box-shadow: 0 -4px 8px rgba(0, 0, 0, 0.1);
  803. transition: transform 0.3s ease-in-out;
  804. transform: translateY(100%); /* 預設隱藏底部視窗 */
  805. &.show {
  806. bottom: 0;
  807. transform: translateY(0);
  808. }
  809. .content {
  810. height: 100%;
  811. display: flex;
  812. position: relative;
  813. flex-direction: column;
  814. align-items: center;
  815. text-align: center;
  816. span {
  817. display: block;
  818. height: 5px;
  819. width: 60px;
  820. position: absolute;
  821. top: 10px;
  822. background: #bbbbbb;
  823. border-radius: 20px;
  824. }
  825. .list {
  826. margin-top: 100px;
  827. }
  828. }
  829. }
  830. </style>