diff --git a/public/icons/constellation_icon.png b/public/icons/constellation_icon.png new file mode 100644 index 0000000..ac5c09f Binary files /dev/null and b/public/icons/constellation_icon.png differ diff --git a/public/icons/game_news_icon.png b/public/icons/game_news_icon.png new file mode 100644 index 0000000..f3f381c Binary files /dev/null and b/public/icons/game_news_icon.png differ diff --git a/public/icons/recommendedIcon.png b/public/icons/recommendedIcon.png new file mode 100644 index 0000000..2ae7d44 Binary files /dev/null and b/public/icons/recommendedIcon.png differ diff --git a/src/layout/adder/WidgetAdder.tsx b/src/layout/adder/WidgetAdder.tsx index 7bd5dd8..10d3ec0 100644 --- a/src/layout/adder/WidgetAdder.tsx +++ b/src/layout/adder/WidgetAdder.tsx @@ -26,7 +26,7 @@ export const WidgetItem = defineComponent({ key={props.content.name} >
- +
(
{ + if (!selected.modal) return router.go(`widget-${props.block.name}`) }} > diff --git a/src/main.css b/src/main.css index 56b04fa..d0ce42b 100644 --- a/src/main.css +++ b/src/main.css @@ -165,6 +165,10 @@ body { scrollbar-width: none; -ms-overflow-style: none; } + +.hover-move:hover { + transform: translateY(-4px); +} @layer utilities { .scrollbar-transparent::-webkit-scrollbar { width: 0; diff --git a/src/widgets/index.ts b/src/widgets/index.ts index 7957d90..434b09c 100644 --- a/src/widgets/index.ts +++ b/src/widgets/index.ts @@ -1,12 +1,13 @@ import type { Component } from 'vue' import calendar from './calendar' import weather from './weather' +import weApply from './weApply' export interface Widget { name: string // 小组件类型唯一标识 label: string // 小组件名称 description: string // 小组件描述 icon: string // 小组件图标 - modal: Component // 弹框组件 + modal: Component | null // 弹框组件 list: { w: number h: number @@ -15,4 +16,4 @@ export interface Widget { }[] // 不同尺寸小组件块 } -export default [calendar, weather] as Widget[] +export default [calendar, weather, weApply] as Widget[] diff --git a/src/widgets/weApply/Large.tsx b/src/widgets/weApply/Large.tsx new file mode 100644 index 0000000..93687aa --- /dev/null +++ b/src/widgets/weApply/Large.tsx @@ -0,0 +1,171 @@ +import { defineComponent, ref, watch, type VNodeRef } from 'vue' +import { useWeApplyStore } from './useWeApplyStore' +import { addIcons, OhVueIcon } from 'oh-vue-icons' +import { HiChevronDown } from 'oh-vue-icons/icons' +import clsx from 'clsx' +addIcons(HiChevronDown) +export default defineComponent(() => { + const store = useWeApplyStore() + const gameRef = ref(null) + const isGameBottom = ref(false) + const isWorkBottom = ref(false) + const workRef = ref(null) + const computIsBottom = (ref: any) => { + if (ref) { + const { scrollTop, clientHeight, scrollHeight } = ref + return scrollTop + clientHeight >= scrollHeight + } + } + const handleGameScroll = () => { + const isAtBottom = computIsBottom(gameRef.value) + console.log(isAtBottom ? '已滚动到底部!' : '未滚动到底部。') + if (isAtBottom) { + isGameBottom.value = true + } else { + isGameBottom.value = false + } + } + const handleWorkScroll = () => { + const isAtBottom = computIsBottom(workRef.value) + console.log(isAtBottom ? '已滚动到底部!' : '未滚动到底部。') + if (isAtBottom) { + isWorkBottom.value = true + } else { + isWorkBottom.value = false + } + } + watch(gameRef, (val, _, onCleanup) => { + console.log(val) + if (!val) return + val.addEventListener('scroll', handleGameScroll) + // if (val + gameRef.value.clientHeight >= gameRef.value.scrollHeight) { + // isGameBottom.value = true + // } else { + // isGameBottom.value = false + // } + onCleanup(() => { + val.removeEventListener('scroll', handleGameScroll) + }) + }) + watch(workRef, (val, _, onCleanup) => { + console.log(val) + if (!val) return + + val.addEventListener('scroll', handleWorkScroll) + // if (val + gameRef.value.clientHeight >= gameRef.value.scrollHeight) { + // isGameBottom.value = true + // } else { + // isGameBottom.value = false + // } + onCleanup(() => { + val.removeEventListener('scroll', handleWorkScroll) + }) + }) + return () => ( +
+
+ {!isGameBottom.value && ( +
{ + e.stopPropagation() + e.preventDefault() + if (gameRef.value) { + gameRef.value.scrollTop += 40 + } + }} + > + +
+ )} + +
{ + console.log('wheel') + }} + > + {store.state.list + .filter((val) => val.type === 'game') + .map((item) => ( +
+ game icon +
+ {item.name} + + {item.des} + +
+
+ ))} +
+
+
+ {!isWorkBottom.value && ( +
{ + e.stopPropagation() + e.preventDefault() + if (workRef.value) { + workRef.value.scrollTop += 20 + } + }} + > + +
+ )} + +
{ + console.log('wheel') + }} + > + {store.state.list + .filter((val) => val.type === 'work') + .map((item) => ( +
+ game icon +
+ {item.name} + + {item.des} + +
+
+ ))} +
+
+
+ ) +}) diff --git a/src/widgets/weApply/index.ts b/src/widgets/weApply/index.ts new file mode 100644 index 0000000..fa76ef1 --- /dev/null +++ b/src/widgets/weApply/index.ts @@ -0,0 +1,18 @@ +import asyncLoader from '@/utils/asyncLoader' +import type { Widget } from '..' + +export default { + name: 'weApply', + label: '大家都在用', + description: '大家都在用', + icon: '/icons/recommendedIcon.png', + modal: null, + list: [ + { + w: 4, + h: 2, + label: '大', + component: asyncLoader(() => import('./Large')) + } + ] +} as Widget diff --git a/src/widgets/weApply/useWeApplyStore.ts b/src/widgets/weApply/useWeApplyStore.ts new file mode 100644 index 0000000..805c66b --- /dev/null +++ b/src/widgets/weApply/useWeApplyStore.ts @@ -0,0 +1,29 @@ +import request from "@/utils/request" +import { defineStore } from "pinia" +import { reactive } from "vue" +type WeApplyType = { + id: string; + name: string; + url: string; + icon: string; + des: string; + type: string; +} +export const useWeApplyStore = defineStore('weApply', () => { + const state = reactive({ + list: [] as WeApplyType[] + }) + const getWeApplyList = async () => { + return request('GET', '/api/app/weApplys').then(res => { + return res + }) + } + const getList = async () => { + state.list = await getWeApplyList() + } + getList() + return { + state, + getList + } +}) \ No newline at end of file