Compare commits
41 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
52602e91a5 | ||
![]() |
e7a4cf7171 | ||
![]() |
777979f0e3 | ||
![]() |
70e7fa534f | ||
![]() |
462aab20af | ||
![]() |
e8b69c5ab5 | ||
![]() |
4b60e7edf1 | ||
![]() |
550545fa3e | ||
![]() |
c068f676d1 | ||
![]() |
c94b230d45 | ||
![]() |
27780c6558 | ||
![]() |
f016348b97 | ||
![]() |
e2290042f7 | ||
![]() |
d085ccc832 | ||
![]() |
78e0d0505a | ||
![]() |
f3dd5b8dc5 | ||
![]() |
a8b1d66330 | ||
![]() |
b28f92b99f | ||
![]() |
1e0fe3e724 | ||
![]() |
c93d7d206b | ||
![]() |
3c2bc226ff | ||
![]() |
015a139ce0 | ||
![]() |
704d446328 | ||
![]() |
b7947467e1 | ||
![]() |
e879efa7d4 | ||
![]() |
df854f3f19 | ||
![]() |
5097e18e31 | ||
![]() |
46b187d01f | ||
![]() |
be94711dc8 | ||
![]() |
6c58920f77 | ||
![]() |
17b278f467 | ||
![]() |
1f8afa7268 | ||
![]() |
418d73caba | ||
![]() |
9c03de74f8 | ||
![]() |
1716f53864 | ||
![]() |
8cb8aba71f | ||
![]() |
802cca0f44 | ||
![]() |
75c75fff0f | ||
![]() |
40e45a539c | ||
![]() |
981320feb2 | ||
![]() |
8d23deeb40 |
15
.dockerignore
Normal file
15
.dockerignore
Normal file
@ -0,0 +1,15 @@
|
||||
node_modules
|
||||
npm-debug.log
|
||||
Dockerfile*
|
||||
docker-compose*
|
||||
.dockerignore
|
||||
.git
|
||||
.github
|
||||
.gitignore
|
||||
README.md
|
||||
LICENSE
|
||||
.vscode
|
||||
dist
|
||||
build
|
||||
images
|
||||
script
|
@ -3,7 +3,7 @@ VITE_SITE_NAME = "無名の主页" # 名称
|
||||
VITE_SITE_ANTHOR = "無名" # 作者
|
||||
VITE_SITE_KEYWORDS = "無名,个人主页" # 关键词
|
||||
VITE_SITE_DES = "一个默默无闻的主页" # 站点简介
|
||||
VITE_SITE_URL = "imsyy.top" # 作者地址
|
||||
VITE_SITE_URL = "imsyy.top" # 站点地址
|
||||
VITE_SITE_LOGO = "/images/icon/favicon.ico" # 站点主图标
|
||||
VITE_SITE_MAIN_LOGO = "/images/icon/logo.png" # 主页图标
|
||||
VITE_SITE_APPLE_LOGO = "/images/logo/apple-touch-icon.png" # Apple 端图标
|
||||
@ -26,7 +26,7 @@ VITE_DESC_TEXT_OTHER = "哎呀,这都被你发现了( 再点击一次可关
|
||||
## 请注意不是 Web端 (JS API),免费申请,每日上限 5000 次
|
||||
## 此处提供的服务可能会超量从而无法访问,请自行申请!请自行申请!请自行申请!
|
||||
## 若此处设为空则调用 教书先生 API https://api.oioweb.cn/doc/weather/GetWeather
|
||||
VITE_WEATHER_KEY = "6c13af6fc30868bee488faf2cc652ab4"
|
||||
VITE_WEATHER_KEY = ""
|
||||
|
||||
# 建站日期
|
||||
## 若不需要,请设为空即可
|
||||
@ -47,5 +47,5 @@ VITE_SONG_API = "https://api-meting.imsyy.top/api"
|
||||
VITE_SONG_SERVER = "netease"
|
||||
# 播放类型 ( song-歌曲, playlist-播放列表, album-专辑, search-搜索, artist-艺术家 )
|
||||
VITE_SONG_TYPE = "playlist"
|
||||
# 播放 ID
|
||||
VITE_SONG_ID = "7452421335"
|
||||
# 播放 ID ( 若无需播放器,请设为空即可 )
|
||||
VITE_SONG_ID = "9379831714"
|
3
.eslintignore
Normal file
3
.eslintignore
Normal file
@ -0,0 +1,3 @@
|
||||
node_modules
|
||||
dist
|
||||
.gitignore
|
35
.eslintrc.json
Normal file
35
.eslintrc.json
Normal file
@ -0,0 +1,35 @@
|
||||
{
|
||||
"env": {
|
||||
"browser": true,
|
||||
"es2021": true
|
||||
},
|
||||
"extends": ["eslint:recommended", "plugin:vue/vue3-essential"],
|
||||
"parserOptions": {
|
||||
"ecmaVersion": "latest",
|
||||
"sourceType": "module"
|
||||
},
|
||||
"plugins": ["vue"],
|
||||
"rules": {
|
||||
"vue/multi-word-component-names": "off"
|
||||
},
|
||||
"globals": {
|
||||
"defineProps": true,
|
||||
"defineEmits": true,
|
||||
"withDefaults": true,
|
||||
"h": true,
|
||||
"vue": true,
|
||||
"ref": true,
|
||||
"reactive": true,
|
||||
"computed": true,
|
||||
"watch": true,
|
||||
"provide": true,
|
||||
"inject": true,
|
||||
"defineComponent": true,
|
||||
"onBeforeMount": true,
|
||||
"onMounted": true,
|
||||
"onBeforeUnmount": true,
|
||||
"nextTick": true,
|
||||
"ElMessage": true,
|
||||
"$openList": true
|
||||
}
|
||||
}
|
46
.github/workflows/build.yml
vendored
Normal file
46
.github/workflows/build.yml
vendored
Normal file
@ -0,0 +1,46 @@
|
||||
# Dev 分支推送部署预览
|
||||
## 仅部署 Win 端
|
||||
name: Build Dev
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- dev
|
||||
- master
|
||||
|
||||
jobs:
|
||||
release:
|
||||
name: Build Website
|
||||
runs-on: windows-latest
|
||||
|
||||
steps:
|
||||
# 检出 Git 仓库
|
||||
- name: Check out git repository
|
||||
uses: actions/checkout@v4.1.1
|
||||
# 安装 Node.js
|
||||
- name: Install Node.js
|
||||
uses: actions/setup-node@v4.0.0
|
||||
with:
|
||||
node-version: "18.x"
|
||||
# 复制环境变量文件
|
||||
- name: Copy .env.example
|
||||
run: |
|
||||
if (-not (Test-Path .env)) {
|
||||
Copy-Item .env.example .env
|
||||
} else {
|
||||
Write-Host ".env file already exists. Skipping the copy step."
|
||||
}
|
||||
# 安装项目依赖
|
||||
- name: Install Dependencies
|
||||
run: npm install
|
||||
# 构建程序
|
||||
- name: Build Website
|
||||
run: npm run build
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.ACCESS_TOKEN }}
|
||||
# 上传构建产物
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v3.1.3
|
||||
with:
|
||||
name: Home
|
||||
path: dist
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -11,6 +11,7 @@ node_modules
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
.env
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
|
8
.prettierrc.json
Normal file
8
.prettierrc.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/prettierrc",
|
||||
"singleQuote": false,
|
||||
"trailingComma": "all",
|
||||
"tabWidth": 2,
|
||||
"semi": true,
|
||||
"printWidth": 100
|
||||
}
|
17
Dockerfile
Normal file
17
Dockerfile
Normal file
@ -0,0 +1,17 @@
|
||||
# 构建应用
|
||||
FROM node:18 AS builder
|
||||
WORKDIR /app
|
||||
COPY package*.json ./
|
||||
RUN npm install
|
||||
COPY . .
|
||||
RUN [ ! -e ".env" ] && cp .env.example .env || true
|
||||
RUN npm run build
|
||||
|
||||
# 最小化镜像
|
||||
FROM node:18-alpine
|
||||
WORKDIR /app
|
||||
COPY --from=builder /app/dist ./dist
|
||||
RUN npm install -g http-server
|
||||
|
||||
EXPOSE 12445
|
||||
CMD ["http-server", "dist", "-p", "12445"]
|
96
README.md
96
README.md
@ -5,19 +5,19 @@
|
||||
简单的小主页,原来的看够了,重新弄了一个
|
||||
</p>
|
||||
|
||||

|
||||

|
||||
|
||||
>主页的 Logo 字体已经过压缩,若用本站 Logo 以外的字母会变回默认字体,这里是 [完整字体](https://file.imsyy.top/font/Other/Pacifico-Regular.ttf)
|
||||
> 主页的 Logo 字体已经过压缩,若用本站 Logo 以外的字母会变回默认字体,这里是 [完整字体](https://file.imsyy.top/font/Other/Pacifico-Regular.ttf),若无法下载,可将字体目录下的 `Pacifico-Regular-all.ttf` 进行替换
|
||||
|
||||
### Demo
|
||||
### 👀 Demo
|
||||
|
||||
>由于 CDN 缓存原因,查看最新效果可能需要 `Ctrl` + `F5` 强制刷新浏览器缓存
|
||||
> 由于 CDN 缓存原因,查看最新效果可能需要 `Ctrl` + `F5` 强制刷新浏览器缓存
|
||||
|
||||
- [無名の主页](https://www.imsyy.top)
|
||||
- [無名の主页 - Dev](https://dev.home-5iw.pages.dev/)
|
||||
- [無名の主页 - 备用线路](https://home-imsyy.vercel.app/)
|
||||
- [無名の主页 - Dev](https://home-imsyy.vercel.app)
|
||||
- [無名の主页 - 备用线路](https://home-5iw.pages.dev)
|
||||
|
||||
### 功能
|
||||
### 🎉 功能
|
||||
|
||||
- [x] 载入动画
|
||||
- [x] 站点简介
|
||||
@ -28,15 +28,27 @@
|
||||
- [x] 音乐播放器
|
||||
- [x] 移动端适配
|
||||
|
||||
### 部署
|
||||
### ⚙️ 自动部署
|
||||
|
||||
* **安装** [node.js](https://nodejs.org/zh-cn/) **环境**
|
||||
如果遇到构建环境或者打包过程出现错误,则可以采用 `Github Actions` 来进行自动构建
|
||||
|
||||
- 在成功 `fork` 仓库后,前往 `Actions` 页面,若您是首次开启,则会出现下面的提示,点击开启
|
||||
|
||||

|
||||
|
||||
- 然后在仓库中进行任意修改后均会触发工作流的运行,在工作流完成后,会在下方生成一个可供下载的压缩包,这就是构建出的静态文件,可自行上传至服务器
|
||||
|
||||

|
||||
|
||||
### ⚙️ 手动部署
|
||||
|
||||
- **安装** [node.js](https://nodejs.org/zh-cn/) **环境**
|
||||
|
||||
> node > 16.16.0
|
||||
> npm > 8.15.0
|
||||
|
||||
* 然后以 **管理员权限** 运行 `cmd` 终端,并 `cd` 到 项目根目录
|
||||
* 在 `终端` 中输入:
|
||||
- 然后以 **管理员权限** 运行 `cmd` 终端,并 `cd` 到 项目根目录
|
||||
- 在 `终端` 中输入:
|
||||
|
||||
```bash
|
||||
# 安装 pnpm
|
||||
@ -51,8 +63,29 @@ pnpm dev
|
||||
# 构建
|
||||
pnpm build
|
||||
```
|
||||
|
||||
> 构建完成后,静态资源会在 **`dist` 目录** 中生成,可将 **`dist` 文件夹下的文件**上传至服务器,也可使用 `Vercel` 等托管平台一键导入并自动部署
|
||||
|
||||
### ⚙️ Docker 部署
|
||||
|
||||
> 安装及配置 Docker 将不在此处说明,请自行解决
|
||||
|
||||
```bash
|
||||
# 构建
|
||||
docker build -t home .
|
||||
# 运行
|
||||
docker run -p 12445:12445 -d home
|
||||
```
|
||||
|
||||
### ⚙️ Vercel 部署
|
||||
|
||||
> 其他部署平台大致相同,在此不做说明
|
||||
|
||||
1. 点击本仓库右上角的 `Fork`,复制本仓库到你的 `GitHub` 账号
|
||||
2. 复制 `/.env.example` 文件并重命名为 `/.env`( 重要 )
|
||||
3. 按需修改 `/.env` 文件中的配置
|
||||
4. 点击 `Deploy`,即可成功部署
|
||||
|
||||
### 网站链接
|
||||
|
||||
在 `src/assets/siteLinks.json` 中可以自定义网站链接(以指向自己的网站):
|
||||
@ -107,11 +140,10 @@ const siteIcon = {
|
||||
|
||||
也可自行更换其他方式
|
||||
|
||||
|
||||
### 音乐
|
||||
|
||||
>本项目采用了基于 `MetingJS` 的 `Aplayer` 音乐播放器,可实现快速自定义歌单
|
||||
>*仅支持 **中国大陆地区**
|
||||
> 本项目采用了基于 `MetingJS` 的 `Aplayer` 音乐播放器,可实现快速自定义歌单
|
||||
> \*仅支持 **中国大陆地区**
|
||||
|
||||
请在 `.env` 文件中更改歌曲相关参数即可实现自定义歌单列表
|
||||
|
||||
@ -130,14 +162,14 @@ VITE_SONG_ID = "7452421335"
|
||||
|
||||
现采用 `HarmonyOS Sans` 开源字体,采用字体拆分,提升加载速度
|
||||
|
||||
>由于本站 `CDN` 已开启防盗链,**非本站域名不可访问**,请将字体引入链接更改为下方内容,否则 **自定义字体将失效**
|
||||
> 由于本站 `CDN` 已开启防盗链,**非本站域名不可访问**,请将字体引入链接更改为下方内容,否则 **自定义字体将失效**
|
||||
>
|
||||
>`https://s1.hdslb.com/bfs/static/jinkela/long/font/regular.css`
|
||||
> `https://s1.hdslb.com/bfs/static/jinkela/long/font/regular.css`
|
||||
|
||||
<details>
|
||||
<summary>旧版方式</summary>
|
||||
|
||||
>由于本项目引入了中文字体,需要压缩中文字体以提高网页加载速度( 也可以取消使用中文字体 )
|
||||
> 由于本项目引入了中文字体,需要压缩中文字体以提高网页加载速度( 也可以取消使用中文字体 )
|
||||
|
||||
#### 中文字体去除繁体
|
||||
|
||||
@ -165,7 +197,7 @@ make clean all
|
||||
|
||||
- 最终可对原字体进行缓加载,**先行加载压缩后的字体**
|
||||
|
||||
>详细信息可前往 [虹墨空间站](https://www.imaegoo.com/2020/chinese-font-compress/) 查看原文
|
||||
> 详细信息可前往 [虹墨空间站](https://www.imaegoo.com/2020/chinese-font-compress/) 查看原文
|
||||
|
||||
</details>
|
||||
|
||||
@ -178,12 +210,9 @@ make clean all
|
||||
如果想要添加更多的本地图片作为网站背景,可以将图片重命名 `background+数字` 的形式,并在 `src/components/Background/index.vue` 中进行修改:
|
||||
|
||||
```js
|
||||
|
||||
if (type == 0) {
|
||||
// 修改此处 Math.random() 后面的第一个数字为图片的数量
|
||||
bgUrl.value = `/images/background${Math.floor(
|
||||
Math.random() * 10 + 1
|
||||
)}.webp`;
|
||||
bgUrl.value = `/images/background${Math.floor(Math.random() * 10 + 1)}.webp`;
|
||||
}
|
||||
```
|
||||
|
||||
@ -193,20 +222,21 @@ if (type == 0) {
|
||||
|
||||
### 技术栈
|
||||
|
||||
* [Vue](https://cn.vuejs.org/)
|
||||
* [Vite](https://vitejs.cn/vite3-cn/)
|
||||
* [Pinia](https://pinia.vuejs.org/zh/)
|
||||
* [IconPark](https://iconpark.oceanengine.com/official)
|
||||
* [xicons](https://xicons.org/)
|
||||
* [Aplayer](https://aplayer.js.org/)
|
||||
- [Vue](https://cn.vuejs.org/)
|
||||
- [Vite](https://vitejs.cn/vite3-cn/)
|
||||
- [Pinia](https://pinia.vuejs.org/zh/)
|
||||
- [IconPark](https://iconpark.oceanengine.com/official)
|
||||
- [xicons](https://xicons.org/)
|
||||
- [Aplayer](https://aplayer.js.org/)
|
||||
|
||||
### API
|
||||
|
||||
* [MetingAPI By 武恩赐](https://api.wuenci.com/meting/api/)
|
||||
* [搏天 API](https://api.btstu.cn/doc/sjbz.php)
|
||||
* [高德开放平台](https://lbs.amap.com/)
|
||||
* [Hitokoto 一言](https://hitokoto.cn/)
|
||||
*
|
||||
- [韩小韩 WebAPI 接口](https://api.vvhan.com/)
|
||||
- [搏天 API](https://api.btstu.cn/doc/sjbz.php)
|
||||
- [教书先生 API](https://api.oioweb.cn/doc/weather/GetWeather)
|
||||
- [高德开放平台](https://lbs.amap.com/)
|
||||
- [Hitokoto 一言](https://hitokoto.cn/)
|
||||
|
||||
## Star History
|
||||
|
||||
[](https://star-history.com/#imsyy/home&Date)
|
||||
|
@ -14,7 +14,8 @@ Simple little homepage, had enough of the original one and made a new one
|
||||
>Due to CDN caching, you may need `Ctrl` + `F5` to force a browser cache refresh to see the latest results
|
||||
|
||||
- [無名の主页](https://www.imsyy.top)
|
||||
- [無名の主页 - 备用线路](https://home-imsyy.vercel.app/)
|
||||
- [無名の主页 - Dev](https://home-imsyy.vercel.app)
|
||||
- [無名の主页 - Standby](https://home-5iw.pages.dev)
|
||||
|
||||
### Functions
|
||||
|
||||
@ -135,7 +136,7 @@ make clean all
|
||||
|
||||
### API
|
||||
|
||||
* [MetingAPI By 武恩赐](https://api.wuenci.com/meting/api/)
|
||||
* [韩小韩 WebAPI 接口](https://api.vvhan.com/)
|
||||
* [搏天 API](https://api.btstu.cn/doc/sjbz.php)
|
||||
* [高德开放平台](https://lbs.amap.com/)
|
||||
* [Hitokoto 一言](https://hitokoto.cn/)
|
||||
|
57
auto-imports.d.ts
vendored
Normal file
57
auto-imports.d.ts
vendored
Normal file
@ -0,0 +1,57 @@
|
||||
// Generated by 'unplugin-auto-import'
|
||||
export {}
|
||||
declare global {
|
||||
const EffectScope: typeof import('vue')['EffectScope']
|
||||
const ElMessage: typeof import('element-plus/es')['ElMessage']
|
||||
const computed: typeof import('vue')['computed']
|
||||
const createApp: typeof import('vue')['createApp']
|
||||
const customRef: typeof import('vue')['customRef']
|
||||
const defineAsyncComponent: typeof import('vue')['defineAsyncComponent']
|
||||
const defineComponent: typeof import('vue')['defineComponent']
|
||||
const effectScope: typeof import('vue')['effectScope']
|
||||
const getCurrentInstance: typeof import('vue')['getCurrentInstance']
|
||||
const getCurrentScope: typeof import('vue')['getCurrentScope']
|
||||
const h: typeof import('vue')['h']
|
||||
const inject: typeof import('vue')['inject']
|
||||
const isProxy: typeof import('vue')['isProxy']
|
||||
const isReactive: typeof import('vue')['isReactive']
|
||||
const isReadonly: typeof import('vue')['isReadonly']
|
||||
const isRef: typeof import('vue')['isRef']
|
||||
const markRaw: typeof import('vue')['markRaw']
|
||||
const nextTick: typeof import('vue')['nextTick']
|
||||
const onActivated: typeof import('vue')['onActivated']
|
||||
const onBeforeMount: typeof import('vue')['onBeforeMount']
|
||||
const onBeforeUnmount: typeof import('vue')['onBeforeUnmount']
|
||||
const onBeforeUpdate: typeof import('vue')['onBeforeUpdate']
|
||||
const onDeactivated: typeof import('vue')['onDeactivated']
|
||||
const onErrorCaptured: typeof import('vue')['onErrorCaptured']
|
||||
const onMounted: typeof import('vue')['onMounted']
|
||||
const onRenderTracked: typeof import('vue')['onRenderTracked']
|
||||
const onRenderTriggered: typeof import('vue')['onRenderTriggered']
|
||||
const onScopeDispose: typeof import('vue')['onScopeDispose']
|
||||
const onServerPrefetch: typeof import('vue')['onServerPrefetch']
|
||||
const onUnmounted: typeof import('vue')['onUnmounted']
|
||||
const onUpdated: typeof import('vue')['onUpdated']
|
||||
const provide: typeof import('vue')['provide']
|
||||
const reactive: typeof import('vue')['reactive']
|
||||
const readonly: typeof import('vue')['readonly']
|
||||
const ref: typeof import('vue')['ref']
|
||||
const resolveComponent: typeof import('vue')['resolveComponent']
|
||||
const resolveDirective: typeof import('vue')['resolveDirective']
|
||||
const shallowReactive: typeof import('vue')['shallowReactive']
|
||||
const shallowReadonly: typeof import('vue')['shallowReadonly']
|
||||
const shallowRef: typeof import('vue')['shallowRef']
|
||||
const toRaw: typeof import('vue')['toRaw']
|
||||
const toRef: typeof import('vue')['toRef']
|
||||
const toRefs: typeof import('vue')['toRefs']
|
||||
const triggerRef: typeof import('vue')['triggerRef']
|
||||
const unref: typeof import('vue')['unref']
|
||||
const useAttrs: typeof import('vue')['useAttrs']
|
||||
const useCssModule: typeof import('vue')['useCssModule']
|
||||
const useCssVars: typeof import('vue')['useCssVars']
|
||||
const useSlots: typeof import('vue')['useSlots']
|
||||
const watch: typeof import('vue')['watch']
|
||||
const watchEffect: typeof import('vue')['watchEffect']
|
||||
const watchPostEffect: typeof import('vue')['watchPostEffect']
|
||||
const watchSyncEffect: typeof import('vue')['watchSyncEffect']
|
||||
}
|
35
components.d.ts
vendored
Normal file
35
components.d.ts
vendored
Normal file
@ -0,0 +1,35 @@
|
||||
// generated by unplugin-vue-components
|
||||
// We suggest you to commit this file into source control
|
||||
// Read more: https://github.com/vuejs/core/pull/3399
|
||||
import '@vue/runtime-core'
|
||||
|
||||
export {}
|
||||
|
||||
declare module '@vue/runtime-core' {
|
||||
export interface GlobalComponents {
|
||||
Background: typeof import('./src/components/Background.vue')['default']
|
||||
ElCard: typeof import('element-plus/es')['ElCard']
|
||||
ElCol: typeof import('element-plus/es')['ElCol']
|
||||
ElCollapse: typeof import('element-plus/es')['ElCollapse']
|
||||
ElCollapseItem: typeof import('element-plus/es')['ElCollapseItem']
|
||||
ElProgress: typeof import('element-plus/es')['ElProgress']
|
||||
ElRadio: typeof import('element-plus/es')['ElRadio']
|
||||
ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup']
|
||||
ElRow: typeof import('element-plus/es')['ElRow']
|
||||
ElSlider: typeof import('element-plus/es')['ElSlider']
|
||||
ElSwitch: typeof import('element-plus/es')['ElSwitch']
|
||||
ElTooltip: typeof import('element-plus/es')['ElTooltip']
|
||||
Footer: typeof import('./src/components/Footer.vue')['default']
|
||||
Hitokoto: typeof import('./src/components/Hitokoto.vue')['default']
|
||||
Links: typeof import('./src/components/Links.vue')['default']
|
||||
Loading: typeof import('./src/components/Loading.vue')['default']
|
||||
Message: typeof import('./src/components/Message.vue')['default']
|
||||
MoreContent: typeof import('./src/components/MoreContent.vue')['default']
|
||||
Music: typeof import('./src/components/Music.vue')['default']
|
||||
Player: typeof import('./src/components/Player.vue')['default']
|
||||
Set: typeof import('./src/components/Set.vue')['default']
|
||||
SocialLinks: typeof import('./src/components/SocialLinks.vue')['default']
|
||||
TimeCapsule: typeof import('./src/components/TimeCapsule.vue')['default']
|
||||
Weather: typeof import('./src/components/Weather.vue')['default']
|
||||
}
|
||||
}
|
9
docker-compose.yml
Normal file
9
docker-compose.yml
Normal file
@ -0,0 +1,9 @@
|
||||
version: '3'
|
||||
|
||||
services:
|
||||
app:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
ports:
|
||||
- "12445:12445"
|
21
index.html
21
index.html
@ -1,12 +1,11 @@
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="zh-CN">
|
||||
|
||||
<head>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta http-equiv="Access-Control-Allow-Origin" content="*">
|
||||
<meta http-equiv="Access-Control-Allow-Origin" content="*" />
|
||||
<!-- <meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests"> -->
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<link rel="icon" href="%VITE_SITE_LOGO%">
|
||||
<link rel="icon" href="%VITE_SITE_LOGO%" />
|
||||
<link rel="apple-touch-icon" href="%VITE_SITE_APPLE_LOGO%" />
|
||||
<link rel="bookmark" href="%VITE_SITE_APPLE_LOGO%" />
|
||||
<link rel="apple-touch-icon-precomposed" sizes="200x200" href="%VITE_SITE_APPLE_LOGO%" />
|
||||
@ -21,13 +20,14 @@
|
||||
<!-- <link rel="stylesheet" href="https://cdn.imsyy.top/gh/imsyy/file/font/HarmonyOS_Sans/regular.min.css" /> -->
|
||||
<!-- IE Out -->
|
||||
<script>
|
||||
if ( /*@cc_on!@*/ false || (!!window.MSInputMethodContext && !!document.documentMode))
|
||||
if (/*@cc_on!@*/ false || (!!window.MSInputMethodContext && !!document.documentMode))
|
||||
window.location.href =
|
||||
"https://support.dmeng.net/upgrade-your-browser.html?referrer=" + encodeURIComponent(window.location.href)
|
||||
'https://support.dmeng.net/upgrade-your-browser.html?referrer=' +
|
||||
encodeURIComponent(window.location.href);
|
||||
</script>
|
||||
</head>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<body>
|
||||
<!-- 主体内容 -->
|
||||
<div id="app"></div>
|
||||
<!-- noscript -->
|
||||
@ -35,6 +35,5 @@
|
||||
<div style="text-align: center">请开启 JavaScript</div>
|
||||
</noscript>
|
||||
<script type="module" src="/src/main.js"></script>
|
||||
</body>
|
||||
|
||||
</body>
|
||||
</html>
|
3691
package-lock.json
generated
3691
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
40
package.json
40
package.json
@ -4,35 +4,41 @@
|
||||
"github": "https://github.com/imsyy/home",
|
||||
"home": "https://imsyy.top",
|
||||
"private": true,
|
||||
"version": "4.1.0",
|
||||
"version": "4.1.4",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite --host",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview"
|
||||
"preview": "vite preview",
|
||||
"format": "prettier --write src/",
|
||||
"lint": "eslint . --ext .js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts,.vue --fix"
|
||||
},
|
||||
"dependencies": {
|
||||
"@worstone/vue-aplayer": "^1.0.6",
|
||||
"aplayer": "^1.10.1",
|
||||
"axios": "^1.1.3",
|
||||
"element-plus": "^2.2.18",
|
||||
"fetch-jsonp": "^1.2.3",
|
||||
"pinia": "^2.0.23",
|
||||
"pinia-plugin-persistedstate": "^3.0.0",
|
||||
"swiper": "^9.3.2",
|
||||
"vue": "^3.3.4",
|
||||
"vue3-aplayer": "^1.7.3"
|
||||
"axios": "^1.6.8",
|
||||
"dayjs": "^1.11.10",
|
||||
"element-plus": "^2.7.1",
|
||||
"fetch-jsonp": "^1.3.0",
|
||||
"pinia": "^2.1.7",
|
||||
"pinia-plugin-persistedstate": "^3.2.1",
|
||||
"swiper": "^11.1.1",
|
||||
"vue": "^3.4.24"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@icon-park/vue-next": "^1.4.2",
|
||||
"@vicons/fa": "^0.12.0",
|
||||
"@vicons/utils": "^0.1.4",
|
||||
"@vitejs/plugin-vue": "^4.2.3",
|
||||
"sass": "^1.55.0",
|
||||
"terser": "^5.16.1",
|
||||
"unplugin-auto-import": "^0.11.2",
|
||||
"unplugin-vue-components": "^0.22.8",
|
||||
"vite": "^4.4.5",
|
||||
"@vitejs/plugin-vue": "^4.6.2",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-plugin-vue": "^9.25.0",
|
||||
"prettier": "^3.2.5",
|
||||
"sass": "^1.75.0",
|
||||
"terser": "^5.30.4",
|
||||
"unplugin-auto-import": "^0.11.5",
|
||||
"unplugin-vue-components": "^0.22.12",
|
||||
"vite": "^4.5.3",
|
||||
"vite-plugin-compression": "^0.5.1",
|
||||
"vite-plugin-pwa": "^0.14.1"
|
||||
"vite-plugin-pwa": "^0.14.7"
|
||||
}
|
||||
}
|
||||
|
6530
pnpm-lock.yaml
6530
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
BIN
public/font/Pacifico-Regular-all.ttf
Normal file
BIN
public/font/Pacifico-Regular-all.ttf
Normal file
Binary file not shown.
3
public/font/README.md
Normal file
3
public/font/README.md
Normal file
@ -0,0 +1,3 @@
|
||||
## Logo 字体替换
|
||||
|
||||
可将该文件夹下的 `Pacifico-Regular-all.ttf` 替换原来的 `Pacifico-Regular.ttf`
|
BIN
screenshots/main.jpg
Normal file
BIN
screenshots/main.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 245 KiB |
BIN
screenshots/step1.jpg
Normal file
BIN
screenshots/step1.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 56 KiB |
BIN
screenshots/step2.jpg
Normal file
BIN
screenshots/step2.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 67 KiB |
24
src/App.vue
24
src/App.vue
@ -12,11 +12,7 @@
|
||||
<MainRight v-show="!store.boxOpenState" />
|
||||
<Box v-show="store.boxOpenState" />
|
||||
</section>
|
||||
<section
|
||||
class="more"
|
||||
v-show="store.setOpenState"
|
||||
@click="store.setOpenState = false"
|
||||
>
|
||||
<section class="more" v-show="store.setOpenState" @click="store.setOpenState = false">
|
||||
<MoreSet />
|
||||
</section>
|
||||
</div>
|
||||
@ -24,6 +20,7 @@
|
||||
<Icon
|
||||
class="menu"
|
||||
size="24"
|
||||
v-show="!store.backgroundShow"
|
||||
@click="store.mobileOpenState = !store.mobileOpenState"
|
||||
>
|
||||
<component :is="store.mobileOpenState ? CloseSmall : HamburgerButton" />
|
||||
@ -74,7 +71,7 @@ watch(
|
||||
if (value < 990) {
|
||||
store.boxOpenState = false;
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
onMounted(() => {
|
||||
@ -107,8 +104,7 @@ onMounted(() => {
|
||||
window.addEventListener("resize", getWidth);
|
||||
|
||||
// 控制台输出
|
||||
const styleTitle1 =
|
||||
"font-size: 20px;font-weight: 600;color: rgb(244,167,89);";
|
||||
const styleTitle1 = "font-size: 20px;font-weight: 600;color: rgb(244,167,89);";
|
||||
const styleTitle2 = "font-size:12px;color: rgb(244,167,89);";
|
||||
const styleContent = "color: rgb(30,152,255);";
|
||||
const title1 = "無名の主页";
|
||||
@ -120,12 +116,7 @@ onMounted(() => {
|
||||
_| |_| | | |____) | | | | |
|
||||
|_____|_| |_|_____/ |_| |_|`;
|
||||
const content = `\n\n版本: ${config.version}\n主页: ${config.home}\nGithub: ${config.github}`;
|
||||
console.info(
|
||||
`%c${title1} %c${title2} %c${content}`,
|
||||
styleTitle1,
|
||||
styleTitle2,
|
||||
styleContent
|
||||
);
|
||||
console.info(`%c${title1} %c${title2} %c${content}`, styleTitle1, styleTitle2, styleContent);
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
@ -142,8 +133,7 @@ onBeforeUnmount(() => {
|
||||
height: 100%;
|
||||
transform: scale(1.2);
|
||||
transition: transform 0.3s;
|
||||
animation: fade-blur-main-in 0.65s cubic-bezier(0.25, 0.46, 0.45, 0.94)
|
||||
forwards;
|
||||
animation: fade-blur-main-in 0.65s cubic-bezier(0.25, 0.46, 0.45, 0.94) forwards;
|
||||
animation-delay: 0.5s;
|
||||
.container {
|
||||
width: 100%;
|
||||
@ -193,7 +183,7 @@ onBeforeUnmount(() => {
|
||||
.i-icon {
|
||||
transform: translateY(2px);
|
||||
}
|
||||
@media (min-width: 720px) {
|
||||
@media (min-width: 721px) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
@ -8,14 +8,13 @@ import fetchJsonp from "fetch-jsonp";
|
||||
// 获取音乐播放列表
|
||||
export const getPlayerList = async (server, type, id) => {
|
||||
const res = await fetch(
|
||||
`${import.meta.env.VITE_SONG_API}?server=${server}&type=${type}&id=${id}`
|
||||
`${import.meta.env.VITE_SONG_API}?server=${server}&type=${type}&id=${id}`,
|
||||
);
|
||||
const data = await res.json();
|
||||
|
||||
if (data[0].url.startsWith("@")) {
|
||||
const [handle, jsonpCallback, jsonpCallbackFunction, url] = data[0].url
|
||||
.split("@")
|
||||
.slice(1);
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const [handle, jsonpCallback, jsonpCallbackFunction, url] = data[0].url.split("@").slice(1);
|
||||
const jsonpData = await fetchJsonp(url).then((res) => res.json());
|
||||
const domain = (
|
||||
jsonpData.req_0.data.sip.find((i) => !i.startsWith("http://ws")) ||
|
||||
@ -23,18 +22,18 @@ export const getPlayerList = async (server, type, id) => {
|
||||
).replace("http://", "https://");
|
||||
|
||||
return data.map((v, i) => ({
|
||||
title: v.name || v.title,
|
||||
name: v.name || v.title,
|
||||
artist: v.artist || v.author,
|
||||
src: domain + jsonpData.req_0.data.midurlinfo[i].purl,
|
||||
pic: v.pic,
|
||||
url: domain + jsonpData.req_0.data.midurlinfo[i].purl,
|
||||
cover: v.cover || v.pic,
|
||||
lrc: v.lrc,
|
||||
}));
|
||||
} else {
|
||||
return data.map((v) => ({
|
||||
title: v.name || v.title,
|
||||
name: v.name || v.title,
|
||||
artist: v.artist || v.author,
|
||||
src: v.url,
|
||||
pic: v.pic,
|
||||
url: v.url,
|
||||
cover: v.cover || v.pic,
|
||||
lrc: v.lrc,
|
||||
}));
|
||||
}
|
||||
@ -63,7 +62,7 @@ export const getAdcode = async (key) => {
|
||||
// 获取高德地理天气信息
|
||||
export const getWeather = async (key, city) => {
|
||||
const res = await fetch(
|
||||
`https://restapi.amap.com/v3/weather/weatherInfo?key=${key}&city=${city}`
|
||||
`https://restapi.amap.com/v3/weather/weatherInfo?key=${key}&city=${city}`,
|
||||
);
|
||||
return await res.json();
|
||||
};
|
||||
|
@ -1,31 +1,38 @@
|
||||
[{
|
||||
[
|
||||
{
|
||||
"name": "Github",
|
||||
"icon": "/images/icon/github.png",
|
||||
"tip": "去 Github 看看",
|
||||
"url": "https://github.com/imsyy"
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"name": "BiliBili",
|
||||
"icon": "/images/icon/bilibili.png",
|
||||
"tip": "(゜-゜)つロ 干杯 ~",
|
||||
"url": "https://space.bilibili.com/98544142"
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"name": "QQ",
|
||||
"icon": "/images/icon/qq.png",
|
||||
"tip": "有什么事吗",
|
||||
"url": "https://res.abeim.cn/api/qq/?qq=1539250352"
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"name": "Email",
|
||||
"icon": "/images/icon/email.png",
|
||||
"tip": "来封 Email ~",
|
||||
"url": "mailto:one@imsyy.top"
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"name": "Twitter",
|
||||
"icon": "/images/icon/twitter.png",
|
||||
"tip": "你懂的 ~",
|
||||
"url": "https://twitter.com/iimmsyy"
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"name": "Telegram",
|
||||
"icon": "/images/icon/telegram.png",
|
||||
"tip": "你懂的 ~",
|
||||
"url": "https://t.me/bottom_user"
|
||||
}]
|
||||
}
|
||||
]
|
||||
|
@ -1,10 +1,10 @@
|
||||
<template>
|
||||
<div class="cover">
|
||||
<div :class="store.backgroundShow ? 'cover show' : 'cover'">
|
||||
<img
|
||||
v-show="store.imgLoadStatus"
|
||||
:src="bgUrl"
|
||||
class="bg"
|
||||
alt="cover"
|
||||
:src="bgUrl"
|
||||
@load="imgLoadComplete"
|
||||
@error.once="imgLoadError"
|
||||
@animationend="imgAnimationEnd"
|
||||
@ -43,17 +43,20 @@ const changeBg = (type) => {
|
||||
} else if (type == 1) {
|
||||
bgUrl.value = "https://api.dujin.org/bing/1920.php";
|
||||
} else if (type == 2) {
|
||||
bgUrl.value = "https://api.btstu.cn/sjbz/api.php?lx=fengjing&format=images";
|
||||
bgUrl.value = "https://api.vvhan.com/api/wallpaper/views";
|
||||
} else if (type == 3) {
|
||||
bgUrl.value = "https://api.btstu.cn/sjbz/api.php?lx=dongman&format=images";
|
||||
bgUrl.value = "https://api.vvhan.com/api/wallpaper/acg";
|
||||
}
|
||||
};
|
||||
|
||||
// 图片加载完成
|
||||
const imgLoadComplete = () => {
|
||||
imgTimeout.value = setTimeout(() => {
|
||||
imgTimeout.value = setTimeout(
|
||||
() => {
|
||||
store.setImgLoadStatus(true);
|
||||
}, Math.floor(Math.random() * (600 - 300 + 1)) + 300);
|
||||
},
|
||||
Math.floor(Math.random() * (600 - 300 + 1)) + 300,
|
||||
);
|
||||
};
|
||||
|
||||
// 图片动画完成
|
||||
@ -76,6 +79,14 @@ const imgLoadError = () => {
|
||||
bgUrl.value = `/images/background${bgRandom}.jpg`;
|
||||
};
|
||||
|
||||
// 监听壁纸切换
|
||||
watch(
|
||||
() => store.coverType,
|
||||
(value) => {
|
||||
changeBg(value);
|
||||
},
|
||||
);
|
||||
|
||||
onMounted(() => {
|
||||
// 加载壁纸
|
||||
changeBg(store.coverType);
|
||||
@ -96,6 +107,10 @@ onBeforeUnmount(() => {
|
||||
transition: 0.25s;
|
||||
z-index: -1;
|
||||
|
||||
&.show {
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.bg {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
@ -105,8 +120,10 @@ onBeforeUnmount(() => {
|
||||
object-fit: cover;
|
||||
backface-visibility: hidden;
|
||||
filter: blur(20px) brightness(0.3);
|
||||
transition: filter 0.3s, transform 0.3s;
|
||||
animation: fade-blur-in 1s cubic-bezier(0.25, 0.46, 0.45, 0.94) forwards;
|
||||
transition:
|
||||
filter 0.3s,
|
||||
transform 0.3s;
|
||||
animation: fade-blur-in 0.8s cubic-bezier(0.25, 0.46, 0.45, 0.94) forwards;
|
||||
animation-delay: 0.45s;
|
||||
}
|
||||
.gray {
|
||||
@ -116,10 +133,7 @@ onBeforeUnmount(() => {
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-image: radial-gradient(
|
||||
rgba(0, 0, 0, 0) 0,
|
||||
rgba(0, 0, 0, 0.5) 100%
|
||||
),
|
||||
background-image: radial-gradient(rgba(0, 0, 0, 0) 0, rgba(0, 0, 0, 0.5) 100%),
|
||||
radial-gradient(rgba(0, 0, 0, 0) 33%, rgba(0, 0, 0, 0.3) 166%);
|
||||
|
||||
transition: 1.5s;
|
||||
|
@ -9,7 +9,7 @@
|
||||
-
|
||||
</span>
|
||||
{{ fullYear }}
|
||||
<a :href="SiteUrl">{{ SiteAnthor }}</a>
|
||||
<a :href="siteUrl">{{ siteAnthor }}</a>
|
||||
</span>
|
||||
<!-- 以下信息请不要修改哦 -->
|
||||
<span class="hidden">
|
||||
@ -48,8 +48,16 @@ const fullYear = new Date().getFullYear();
|
||||
// 加载配置数据
|
||||
const siteStartDate = ref(import.meta.env.VITE_SITE_START);
|
||||
const siteIcp = ref(import.meta.env.VITE_SITE_ICP);
|
||||
const SiteAnthor = ref(import.meta.env.VITE_SITE_ANTHOR);
|
||||
const SiteUrl = ref(import.meta.env.VITE_SITE_URL);
|
||||
const siteAnthor = ref(import.meta.env.VITE_SITE_ANTHOR);
|
||||
const siteUrl = computed(() => {
|
||||
const url = import.meta.env.VITE_SITE_URL;
|
||||
if (!url) return "https://www.imsyy.top";
|
||||
// 判断协议前缀
|
||||
if (!url.startsWith("http://") && !url.startsWith("https://")) {
|
||||
return "//" + url;
|
||||
}
|
||||
return url;
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
@ -18,10 +18,12 @@
|
||||
</div>
|
||||
</Transition>
|
||||
<!-- 一言内容 -->
|
||||
<div class="content" @click="updateHitokoto">
|
||||
<Transition name="el-fade-in-linear" mode="out-in">
|
||||
<div :key="hitokotoData.text" class="content" @click="updateHitokoto">
|
||||
<span class="text">{{ hitokotoData.text }}</span>
|
||||
<span class="from">-「 {{ hitokotoData.from }} 」</span>
|
||||
</div>
|
||||
</Transition>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -43,13 +45,12 @@ const hitokotoData = reactive({
|
||||
});
|
||||
|
||||
// 获取一言数据
|
||||
const getHitokotoData = () => {
|
||||
getHitokoto()
|
||||
.then((res) => {
|
||||
hitokotoData.text = res.hitokoto;
|
||||
hitokotoData.from = res.from;
|
||||
})
|
||||
.catch(() => {
|
||||
const getHitokotoData = async () => {
|
||||
try {
|
||||
const result = await getHitokoto();
|
||||
hitokotoData.text = result.hitokoto;
|
||||
hitokotoData.from = result.from;
|
||||
} catch (error) {
|
||||
ElMessage({
|
||||
message: "一言获取失败",
|
||||
icon: h(Error, {
|
||||
@ -57,13 +58,13 @@ const getHitokotoData = () => {
|
||||
fill: "#efefef",
|
||||
}),
|
||||
});
|
||||
});
|
||||
hitokotoData.text = "这里应该显示一句话";
|
||||
hitokotoData.from = "無名";
|
||||
}
|
||||
};
|
||||
|
||||
// 更新一言数据
|
||||
const updateHitokoto = () => {
|
||||
hitokotoData.text = "新的一言正在赶来的路上";
|
||||
hitokotoData.from = "来源加载中";
|
||||
// 防抖
|
||||
debounce(() => {
|
||||
getHitokotoData();
|
||||
|
@ -43,22 +43,11 @@
|
||||
<script setup>
|
||||
import { Icon } from "@vicons/utils";
|
||||
// 可前往 https://www.xicons.org 自行挑选并在此处引入
|
||||
import {
|
||||
Link,
|
||||
Blog,
|
||||
CompactDisc,
|
||||
Cloud,
|
||||
Compass,
|
||||
Book,
|
||||
Fire,
|
||||
LaptopCode,
|
||||
} from "@vicons/fa"; // 注意使用正确的类别
|
||||
import { Link, Blog, CompactDisc, Cloud, Compass, Book, Fire, LaptopCode } from "@vicons/fa"; // 注意使用正确的类别
|
||||
import { mainStore } from "@/store";
|
||||
import { Swiper, SwiperSlide } from "swiper/vue";
|
||||
import { Pagination, Mousewheel } from "swiper";
|
||||
import { Pagination, Mousewheel } from "swiper/modules";
|
||||
import siteLinks from "@/assets/siteLinks.json";
|
||||
import "swiper/scss";
|
||||
import "swiper/scss/pagination";
|
||||
|
||||
const store = mainStore();
|
||||
|
||||
@ -120,14 +109,22 @@ onMounted(() => {
|
||||
height: 100%;
|
||||
}
|
||||
.swiper-pagination {
|
||||
position: static;
|
||||
margin-top: 4px;
|
||||
margin-top: 12px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
:deep(.swiper-pagination-bullet) {
|
||||
background-color: #fff;
|
||||
width: 18px;
|
||||
width: 20px;
|
||||
height: 4px;
|
||||
margin: 0 4px;
|
||||
border-radius: 4px;
|
||||
opacity: 0.2;
|
||||
transition: opacity 0.3s;
|
||||
&.swiper-pagination-bullet-active {
|
||||
opacity: 1;
|
||||
}
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
@ -109,7 +109,9 @@ const siteName = import.meta.env.VITE_SITE_NAME;
|
||||
&.loaded {
|
||||
visibility: hidden;
|
||||
transform: translateY(-100%);
|
||||
transition: transform 0.3s 1s ease-out, visibility 0.3s 1s ease-out;
|
||||
transition:
|
||||
transform 0.3s 1s ease-out,
|
||||
visibility 0.3s 1s ease-out;
|
||||
.loader {
|
||||
.loader-circle,
|
||||
.loader-text {
|
||||
|
@ -4,7 +4,7 @@
|
||||
<!-- Logo -->
|
||||
<div class="logo">
|
||||
<img class="logo-img" :src="siteLogo" alt="logo" />
|
||||
<div class="name text-hidden">
|
||||
<div :class="{ name: true, 'text-hidden': true, long: siteUrl[0].length >= 6 }">
|
||||
<span class="bg">{{ siteUrl[0] }}</span>
|
||||
<span class="sm">.{{ siteUrl[1] }}</span>
|
||||
</div>
|
||||
@ -15,10 +15,12 @@
|
||||
<Icon size="16">
|
||||
<QuoteLeft />
|
||||
</Icon>
|
||||
<div class="text">
|
||||
<Transition name="fade" mode="out-in">
|
||||
<div :key="descriptionText.hello + descriptionText.text" class="text">
|
||||
<p>{{ descriptionText.hello }}</p>
|
||||
<p>{{ descriptionText.text }}</p>
|
||||
</div>
|
||||
</Transition>
|
||||
<Icon size="16">
|
||||
<QuoteRight />
|
||||
</Icon>
|
||||
@ -37,7 +39,16 @@ const store = mainStore();
|
||||
// 主页站点logo
|
||||
const siteLogo = import.meta.env.VITE_SITE_MAIN_LOGO;
|
||||
// 站点链接
|
||||
const siteUrl = import.meta.env.VITE_SITE_URL.split(".");
|
||||
const siteUrl = computed(() => {
|
||||
const url = import.meta.env.VITE_SITE_URL;
|
||||
if (!url) return "imsyy.top".split(".");
|
||||
// 判断协议前缀
|
||||
if (url.startsWith("http://") || url.startsWith("https://")) {
|
||||
const urlFormat = url.replace(/^(https?:\/\/)/, "");
|
||||
return urlFormat.split(".");
|
||||
}
|
||||
return url.split(".");
|
||||
});
|
||||
|
||||
// 简介区域文字
|
||||
const descriptionText = reactive({
|
||||
@ -72,7 +83,7 @@ watch(
|
||||
descriptionText.hello = import.meta.env.VITE_DESC_HELLO;
|
||||
descriptionText.text = import.meta.env.VITE_DESC_TEXT;
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
</script>
|
||||
|
||||
@ -83,14 +94,14 @@ watch(
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
animation: fade 0.5s;
|
||||
max-width: 460px;
|
||||
.logo-img {
|
||||
border-radius: 50%;
|
||||
width: 120px;
|
||||
}
|
||||
.name {
|
||||
width: 100%;
|
||||
height: 142px;
|
||||
margin-left: 12px;
|
||||
padding-left: 22px;
|
||||
transform: translateY(-8px);
|
||||
font-family: "Pacifico-Regular";
|
||||
|
||||
@ -117,6 +128,10 @@ watch(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 720px) {
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.description {
|
||||
@ -133,6 +148,7 @@ watch(
|
||||
margin: 0.75rem 1rem;
|
||||
line-height: 2rem;
|
||||
margin-right: auto;
|
||||
transition: opacity 0.2s;
|
||||
|
||||
p {
|
||||
&:nth-of-type(1) {
|
||||
|
14
src/components/MoreContent.vue
Normal file
14
src/components/MoreContent.vue
Normal file
@ -0,0 +1,14 @@
|
||||
<template>
|
||||
<div class="more-content">您可在此编写任意内容</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.more-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-top: 20px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
@ -11,32 +11,14 @@
|
||||
<span @click="store.musicOpenState = false">回到一言</span>
|
||||
</div>
|
||||
<div class="control">
|
||||
<go-start
|
||||
theme="filled"
|
||||
size="30"
|
||||
fill="#efefef"
|
||||
@click="changeMusicIndex(0)"
|
||||
/>
|
||||
<div class="state" @click="changePlayState">
|
||||
<play-one
|
||||
theme="filled"
|
||||
size="50"
|
||||
fill="#efefef"
|
||||
v-show="!store.playerState"
|
||||
/>
|
||||
<pause
|
||||
theme="filled"
|
||||
size="50"
|
||||
fill="#efefef"
|
||||
v-show="store.playerState"
|
||||
/>
|
||||
<go-start theme="filled" size="30" fill="#efefef" @click="changeMusicIndex(0)" />
|
||||
<Transition name="fade" mode="out-in">
|
||||
<div :key="store.playerState" class="state" @click="changePlayState">
|
||||
<play-one theme="filled" size="50" fill="#efefef" v-show="!store.playerState" />
|
||||
<pause theme="filled" size="50" fill="#efefef" v-show="store.playerState" />
|
||||
</div>
|
||||
<go-end
|
||||
theme="filled"
|
||||
size="30"
|
||||
fill="#efefef"
|
||||
@click="changeMusicIndex(1)"
|
||||
/>
|
||||
</Transition>
|
||||
<go-end theme="filled" size="30" fill="#efefef" @click="changeMusicIndex(1)" />
|
||||
</div>
|
||||
<div class="menu">
|
||||
<div class="name" v-show="!volumeShow">
|
||||
@ -48,12 +30,7 @@
|
||||
</div>
|
||||
<div class="volume" v-show="volumeShow">
|
||||
<div class="icon">
|
||||
<volume-mute
|
||||
theme="filled"
|
||||
size="24"
|
||||
fill="#efefef"
|
||||
v-if="volumeNum == 0"
|
||||
/>
|
||||
<volume-mute theme="filled" size="24" fill="#efefef" v-if="volumeNum == 0" />
|
||||
<volume-small
|
||||
theme="filled"
|
||||
size="24"
|
||||
@ -62,23 +39,13 @@
|
||||
/>
|
||||
<volume-notice theme="filled" size="24" fill="#efefef" v-else />
|
||||
</div>
|
||||
<el-slider
|
||||
v-model="volumeNum"
|
||||
:show-tooltip="false"
|
||||
:min="0"
|
||||
:max="1"
|
||||
:step="0.01"
|
||||
/>
|
||||
<el-slider v-model="volumeNum" :show-tooltip="false" :min="0" :max="1" :step="0.01" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 音乐列表弹窗 -->
|
||||
<Transition name="fade">
|
||||
<div
|
||||
class="music-list"
|
||||
v-show="musicListShow"
|
||||
@click="musicListShow = false"
|
||||
>
|
||||
<Transition name="fade" mode="out-in">
|
||||
<div class="music-list" v-show="musicListShow" @click="closeMusicList()">
|
||||
<Transition name="zoom">
|
||||
<div class="list" v-show="musicListShow" @click.stop>
|
||||
<close-one
|
||||
@ -86,15 +53,14 @@
|
||||
theme="filled"
|
||||
size="28"
|
||||
fill="#ffffff60"
|
||||
@click="musicListShow = false"
|
||||
@click="closeMusicList()"
|
||||
/>
|
||||
<Player
|
||||
ref="playerRef"
|
||||
:songServer="playerData.server"
|
||||
:songType="playerData.type"
|
||||
:songId="playerData.id"
|
||||
:volume="volumeNum"
|
||||
:shuffle="false"
|
||||
ref="playerRef"
|
||||
/>
|
||||
</div>
|
||||
</Transition>
|
||||
@ -133,6 +99,13 @@ const playerData = reactive({
|
||||
// 开启播放列表
|
||||
const openMusicList = () => {
|
||||
musicListShow.value = true;
|
||||
playerRef.value.toggleList();
|
||||
};
|
||||
|
||||
// 关闭播放列表
|
||||
const closeMusicList = () => {
|
||||
musicListShow.value = false;
|
||||
playerRef.value.toggleList();
|
||||
};
|
||||
|
||||
// 音乐播放暂停
|
||||
@ -148,6 +121,9 @@ const changeMusicIndex = (type) => {
|
||||
onMounted(() => {
|
||||
// 空格键事件
|
||||
window.addEventListener("keydown", (e) => {
|
||||
if (!store.musicIsOk) {
|
||||
return;
|
||||
}
|
||||
if (e.code == "Space") {
|
||||
changePlayState();
|
||||
}
|
||||
@ -162,7 +138,7 @@ watch(
|
||||
(value) => {
|
||||
store.musicVolume = value;
|
||||
playerRef.value.changeVolume(store.musicVolume);
|
||||
}
|
||||
},
|
||||
);
|
||||
</script>
|
||||
|
||||
@ -203,6 +179,7 @@ watch(
|
||||
justify-content: space-evenly;
|
||||
width: 100%;
|
||||
.state {
|
||||
transition: opacity 0.1s;
|
||||
.i-icon {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
@ -316,12 +293,6 @@ watch(
|
||||
}
|
||||
|
||||
// 弹窗动画
|
||||
.fade-enter-active {
|
||||
animation: fade 0.3s ease-in-out;
|
||||
}
|
||||
.fade-leave-active {
|
||||
animation: fade 0.3s ease-in-out reverse;
|
||||
}
|
||||
.zoom-enter-active {
|
||||
animation: zoom 0.4s ease-in-out;
|
||||
}
|
||||
|
@ -1,21 +1,22 @@
|
||||
<template>
|
||||
<aplayer
|
||||
showLrc
|
||||
ref="player"
|
||||
<APlayer
|
||||
v-if="playList[0]"
|
||||
:music="playList[playIndex]"
|
||||
:list="playList"
|
||||
:autoplay="autoplay"
|
||||
ref="player"
|
||||
:audio="playList"
|
||||
:autoplay="store.playerAutoplay"
|
||||
:theme="theme"
|
||||
:repeat="repeat"
|
||||
:shuffle="shuffle"
|
||||
:listMaxHeight="listMaxHeight"
|
||||
:listFolded="listFolded"
|
||||
:autoSwitch="false"
|
||||
:loop="store.playerLoop"
|
||||
:order="store.playerOrder"
|
||||
:volume="volume"
|
||||
:showLrc="true"
|
||||
:listFolded="listFolded"
|
||||
:listMaxHeight="listMaxHeight"
|
||||
:noticeSwitch="false"
|
||||
@play="onPlay"
|
||||
@pause="onPause"
|
||||
@timeupdate="onTimeUp"
|
||||
@onSelectSong="onSelectSong"
|
||||
@error="loadMusicError"
|
||||
/>
|
||||
</template>
|
||||
|
||||
@ -23,7 +24,7 @@
|
||||
import { MusicOne, PlayWrong } from "@icon-park/vue-next";
|
||||
import { getPlayerList } from "@/api";
|
||||
import { mainStore } from "@/store";
|
||||
import aplayer from "vue3-aplayer";
|
||||
import APlayer from "@worstone/vue-aplayer";
|
||||
|
||||
const store = mainStore();
|
||||
|
||||
@ -35,30 +36,14 @@ const playList = ref([]);
|
||||
|
||||
// 歌曲播放项
|
||||
const playIndex = ref(0);
|
||||
const playListCount = ref(0);
|
||||
|
||||
// 配置项
|
||||
const props = defineProps({
|
||||
// 音频自动播放
|
||||
autoplay: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
// 主题色
|
||||
theme: {
|
||||
type: String,
|
||||
default: "#efefef",
|
||||
},
|
||||
// 音频循环播放
|
||||
repeat: {
|
||||
type: String,
|
||||
default: "list", //'list' | 'music' | 'none'
|
||||
},
|
||||
// 随机播放
|
||||
shuffle: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
// 默认音量
|
||||
volume: {
|
||||
type: Number,
|
||||
@ -89,42 +74,29 @@ const props = defineProps({
|
||||
},
|
||||
// 列表最大高度
|
||||
listMaxHeight: {
|
||||
type: String,
|
||||
default: "420px",
|
||||
type: Number,
|
||||
default: 420,
|
||||
},
|
||||
});
|
||||
|
||||
const listHeight = computed(() => {
|
||||
return props.listMaxHeight + "px";
|
||||
});
|
||||
|
||||
// 初始化播放器
|
||||
onMounted(() => {
|
||||
nextTick(() => {
|
||||
try {
|
||||
getPlayerList(props.songServer, props.songType, props.songId).then(
|
||||
(res) => {
|
||||
getPlayerList(props.songServer, props.songType, props.songId).then((res) => {
|
||||
console.log(res);
|
||||
// 生成歌单信息
|
||||
playIndex.value = Math.floor(Math.random() * res.length);
|
||||
playListCount.value = res.length;
|
||||
// 更改播放器加载状态
|
||||
store.musicIsOk = true;
|
||||
// 生成歌单
|
||||
res.forEach((v) => {
|
||||
playList.value.push({
|
||||
title: v.name || v.title,
|
||||
artist: v.artist || v.author,
|
||||
src: v.url || v.src,
|
||||
pic: v.pic,
|
||||
lrc: v.lrc,
|
||||
playList.value = res;
|
||||
console.log("音乐加载完成");
|
||||
console.log(playList.value);
|
||||
console.log(playIndex.value, playList.value.length, props.volume);
|
||||
});
|
||||
});
|
||||
console.log(
|
||||
"音乐加载完成",
|
||||
playList.value,
|
||||
playIndex.value,
|
||||
playListCount.value,
|
||||
props.volume
|
||||
);
|
||||
}
|
||||
);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
store.musicIsOk = false;
|
||||
@ -143,13 +115,11 @@ onMounted(() => {
|
||||
// 播放
|
||||
const onPlay = () => {
|
||||
console.log("播放");
|
||||
playIndex.value = player.value.aplayer.index;
|
||||
// 播放状态
|
||||
store.setPlayerState(player.value.audio.paused);
|
||||
store.setPlayerState(player.value.audioRef.paused);
|
||||
// 储存播放器信息
|
||||
store.setPlayerData(
|
||||
player.value.currentMusic.title,
|
||||
player.value.currentMusic.artist
|
||||
);
|
||||
store.setPlayerData(playList.value[playIndex.value].name, playList.value[playIndex.value].artist);
|
||||
ElMessage({
|
||||
message: store.getPlayerData.name + " - " + store.getPlayerData.artist,
|
||||
grouping: true,
|
||||
@ -162,21 +132,23 @@ const onPlay = () => {
|
||||
|
||||
// 暂停
|
||||
const onPause = () => {
|
||||
store.setPlayerState(player.value.audio.paused);
|
||||
store.setPlayerState(player.value.audioRef.paused);
|
||||
};
|
||||
|
||||
// 音频时间更新事件
|
||||
const onTimeUp = () => {
|
||||
let playerRef = player.value.$.vnode.el;
|
||||
if (playerRef) {
|
||||
const currentLrcElement = playerRef.querySelector(".aplayer-lrc-current");
|
||||
const previousLrcElement = currentLrcElement?.previousElementSibling;
|
||||
const lrcContent =
|
||||
currentLrcElement?.innerHTML ||
|
||||
previousLrcElement?.innerHTML ||
|
||||
"这句没有歌词";
|
||||
store.setPlayerLrc(lrcContent);
|
||||
let lyrics = player.value.aplayer.lyrics[playIndex.value];
|
||||
let lyricIndex = player.value.aplayer.lyricIndex;
|
||||
if (!lyrics || !lyrics[lyricIndex]) {
|
||||
return;
|
||||
}
|
||||
let lrc = lyrics[lyricIndex][1];
|
||||
if (lrc === "Loading") {
|
||||
lrc = "歌词加载中";
|
||||
} else if (lrc === "Not available") {
|
||||
lrc = "歌词加载失败";
|
||||
}
|
||||
store.setPlayerLrc(lrc);
|
||||
};
|
||||
|
||||
// 切换播放暂停事件
|
||||
@ -186,40 +158,55 @@ const playToggle = () => {
|
||||
|
||||
// 切换音量事件
|
||||
const changeVolume = (value) => {
|
||||
player.value.audio.volume = value;
|
||||
};
|
||||
|
||||
const onSelectSong = (val) => {
|
||||
console.log(val);
|
||||
player.value.setVolume(value, false);
|
||||
};
|
||||
|
||||
// 切换上下曲
|
||||
const changeSong = (type) => {
|
||||
playIndex.value = player.value.playIndex;
|
||||
playIndex.value += type ? 1 : -1;
|
||||
// 判断是否处于最后/第一首
|
||||
if (playIndex.value < 0) {
|
||||
playIndex.value = playListCount.value - 1;
|
||||
} else if (playIndex.value >= playListCount.value) {
|
||||
playIndex.value = 0;
|
||||
}
|
||||
// console.log(playIndex.value, playList.value[playIndex.value]);
|
||||
type === 0 ? player.value.skipBack() : player.value.skipForward();
|
||||
nextTick(() => {
|
||||
player.value.play();
|
||||
});
|
||||
};
|
||||
|
||||
// 切换歌曲列表状态
|
||||
const toggleList = () => {
|
||||
player.value.toggleList();
|
||||
};
|
||||
|
||||
// 加载音频错误
|
||||
const loadMusicError = () => {
|
||||
let notice = "";
|
||||
if (playList.value.length > 1) {
|
||||
notice = "播放歌曲出现错误,播放器将在 2s 后进行下一首";
|
||||
} else {
|
||||
notice = "播放歌曲出现错误";
|
||||
}
|
||||
ElMessage({
|
||||
message: notice,
|
||||
grouping: true,
|
||||
icon: h(PlayWrong, {
|
||||
theme: "filled",
|
||||
fill: "#EFEFEF",
|
||||
duration: 2000,
|
||||
}),
|
||||
});
|
||||
console.error(
|
||||
"播放歌曲: " + player.value.aplayer.audio[player.value.aplayer.index].name + " 出现错误",
|
||||
);
|
||||
};
|
||||
|
||||
// 暴露子组件方法
|
||||
defineExpose({ playToggle, changeVolume, changeSong });
|
||||
defineExpose({ playToggle, changeVolume, changeSong, toggleList });
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.aplayer {
|
||||
width: 80%;
|
||||
background: transparent;
|
||||
border-radius: 6px;
|
||||
font-family: "HarmonyOS_Regular", sans-serif !important;
|
||||
:deep(.aplayer-body) {
|
||||
background-color: transparent;
|
||||
.aplayer-pic {
|
||||
display: none;
|
||||
}
|
||||
@ -241,8 +228,8 @@ defineExpose({ playToggle, changeVolume, changeSong });
|
||||
}
|
||||
.aplayer-lrc {
|
||||
text-align: left;
|
||||
margin: 4px 0 6px 6px;
|
||||
height: 100%;
|
||||
margin: 7px 0 6px 6px;
|
||||
height: 44px;
|
||||
mask: linear-gradient(
|
||||
#fff 15%,
|
||||
#fff 85%,
|
||||
@ -274,6 +261,8 @@ defineExpose({ playToggle, changeVolume, changeSong });
|
||||
}
|
||||
:deep(.aplayer-list) {
|
||||
margin-top: 6px;
|
||||
height: v-bind(listHeight);
|
||||
background-color: transparent;
|
||||
ol {
|
||||
&::-webkit-scrollbar-track {
|
||||
background-color: transparent;
|
||||
|
@ -3,15 +3,11 @@
|
||||
<el-collapse class="collapse" v-model="activeName" accordion>
|
||||
<el-collapse-item title="个性壁纸" name="1">
|
||||
<div class="bg-set">
|
||||
<el-radio-group
|
||||
v-model="coverType"
|
||||
text-color="#ffffff"
|
||||
@change="radioChange"
|
||||
>
|
||||
<el-radio label="0" size="large" border>默认壁纸</el-radio>
|
||||
<el-radio label="1" size="large" border>每日一图</el-radio>
|
||||
<el-radio label="2" size="large" border>随机风景</el-radio>
|
||||
<el-radio label="3" size="large" border>随机动漫</el-radio>
|
||||
<el-radio-group v-model="coverType" text-color="#ffffff" @change="radioChange">
|
||||
<el-radio value="0" size="large" border>默认壁纸</el-radio>
|
||||
<el-radio value="1" size="large" border>每日一图</el-radio>
|
||||
<el-radio value="2" size="large" border>随机风景</el-radio>
|
||||
<el-radio value="3" size="large" border>随机动漫</el-radio>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
</el-collapse-item>
|
||||
@ -54,7 +50,34 @@
|
||||
</div>
|
||||
</el-collapse-item>
|
||||
<el-collapse-item title="播放器配置" name="3">
|
||||
<div>设置内容待增加</div>
|
||||
<div class="item">
|
||||
<span class="text">自动播放</span>
|
||||
<el-switch
|
||||
v-model="playerAutoplay"
|
||||
inline-prompt
|
||||
:active-icon="CheckSmall"
|
||||
:inactive-icon="CloseSmall"
|
||||
/>
|
||||
</div>
|
||||
<div class="item">
|
||||
<span class="text">随机播放</span>
|
||||
<el-switch
|
||||
v-model="playerOrder"
|
||||
inline-prompt
|
||||
:active-icon="CheckSmall"
|
||||
:inactive-icon="CloseSmall"
|
||||
active-value="random"
|
||||
inactive-value="list"
|
||||
/>
|
||||
</div>
|
||||
<div class="item">
|
||||
<span class="text">循环模式</span>
|
||||
<el-radio-group v-model="playerLoop" size="small" text-color="#FFFFFF">
|
||||
<el-radio value="all" border>列表</el-radio>
|
||||
<el-radio value="one" border>单曲</el-radio>
|
||||
<el-radio value="none" border>不循环</el-radio>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
</el-collapse-item>
|
||||
<el-collapse-item title="其他设置" name="4">
|
||||
<div>设置内容待增加</div>
|
||||
@ -69,8 +92,16 @@ import { mainStore } from "@/store";
|
||||
import { storeToRefs } from "pinia";
|
||||
|
||||
const store = mainStore();
|
||||
const { coverType, siteStartShow, musicClick, playerLrcShow, footerBlur } =
|
||||
storeToRefs(store);
|
||||
const {
|
||||
coverType,
|
||||
siteStartShow,
|
||||
musicClick,
|
||||
playerLrcShow,
|
||||
footerBlur,
|
||||
playerAutoplay,
|
||||
playerOrder,
|
||||
playerLoop,
|
||||
} = storeToRefs(store);
|
||||
|
||||
// 默认选中项
|
||||
const activeName = ref("1");
|
||||
@ -78,7 +109,7 @@ const activeName = ref("1");
|
||||
// 壁纸切换
|
||||
const radioChange = () => {
|
||||
ElMessage({
|
||||
message: "壁纸设置成功,刷新后生效",
|
||||
message: "壁纸更换成功",
|
||||
icon: h(SuccessPicture, {
|
||||
theme: "filled",
|
||||
fill: "#efefef",
|
||||
@ -112,13 +143,23 @@ const radioChange = () => {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
flex-wrap: wrap;
|
||||
font-size: 14px;
|
||||
.el-switch__core {
|
||||
border-color: transparent;
|
||||
background-color: #ffffff30;
|
||||
}
|
||||
.el-radio-group {
|
||||
.el-radio {
|
||||
margin: 2px 10px 2px 0;
|
||||
border-radius: 5px;
|
||||
|
||||
&:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.bg-set {
|
||||
.el-radio-group {
|
||||
justify-content: space-between;
|
||||
|
||||
@ -157,6 +198,5 @@ const radioChange = () => {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -37,7 +37,9 @@ const socialTip = ref("通过这里联系我吧");
|
||||
border-radius: 6px;
|
||||
backdrop-filter: blur(0);
|
||||
animation: fade 0.5s;
|
||||
transition: background-color 0.3s, backdrop-filter 0.3s;
|
||||
transition:
|
||||
background-color 0.3s,
|
||||
backdrop-filter 0.3s;
|
||||
@media (max-width: 840px) {
|
||||
max-width: 100%;
|
||||
justify-content: center;
|
||||
|
@ -1,54 +1,27 @@
|
||||
<template>
|
||||
<div class="time-capsule">
|
||||
<div class="title">
|
||||
<hourglass-full
|
||||
theme="two-tone"
|
||||
size="24"
|
||||
:fill="['#efefef', '#00000020']"
|
||||
/>
|
||||
<hourglass-full theme="two-tone" size="24" :fill="['#efefef', '#00000020']" />
|
||||
<span>时光胶囊</span>
|
||||
</div>
|
||||
<span class="text"
|
||||
>今日已经度过了 {{ timeData.day.elapsed }} 小时</span
|
||||
>
|
||||
<el-progress
|
||||
:text-inside="true"
|
||||
:stroke-width="20"
|
||||
:percentage="timeData.day.pass"
|
||||
/>
|
||||
<span class="text"
|
||||
>本周已经度过了 {{ timeData.week.elapsed }} 天</span
|
||||
>
|
||||
<el-progress
|
||||
:text-inside="true"
|
||||
:stroke-width="20"
|
||||
:percentage="timeData.week.pass"
|
||||
/>
|
||||
<span class="text"
|
||||
>本月已经度过了 {{ timeData.month.elapsed }} 天</span
|
||||
>
|
||||
<el-progress
|
||||
:text-inside="true"
|
||||
:stroke-width="20"
|
||||
:percentage="timeData.month.pass"
|
||||
/>
|
||||
<span class="text"
|
||||
>今年已经度过了 {{ timeData.year.elapsed }} 个月</span
|
||||
>
|
||||
<el-progress
|
||||
:text-inside="true"
|
||||
:stroke-width="20"
|
||||
:percentage="timeData.year.pass"
|
||||
/>
|
||||
<div v-if="startDate?.length >= 4 && store.siteStartShow">
|
||||
<span class="text" v-html="startDateText" />
|
||||
<!-- <el-progress
|
||||
:show-text="false"
|
||||
:indeterminate="true"
|
||||
:stroke-width="6"
|
||||
:percentage="80"
|
||||
:duration="2"
|
||||
/> -->
|
||||
<div v-if="timeData" class="all-capsule">
|
||||
<div v-for="(item, tag, index) in timeData" :key="index" class="capsule-item">
|
||||
<div class="item-title">
|
||||
<span class="percentage">
|
||||
{{ item.name }}已度过
|
||||
<strong>{{ item.passed }}</strong>
|
||||
{{ tag === "day" ? "小时" : "天" }}
|
||||
</span>
|
||||
<span class="remaining">
|
||||
剩余 {{ item.remaining }} {{ tag === "day" ? "小时" : "天" }}
|
||||
</span>
|
||||
</div>
|
||||
<el-progress :text-inside="true" :stroke-width="20" :percentage="item.percentage" />
|
||||
</div>
|
||||
<!-- 建站日期 -->
|
||||
<div v-if="store.siteStartShow" class="capsule-item start">
|
||||
<div class="item-title">{{ startDateText }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@ -68,8 +41,7 @@ const timeInterval = ref(null);
|
||||
onMounted(() => {
|
||||
timeInterval.value = setInterval(() => {
|
||||
timeData.value = getTimeCapsule();
|
||||
if (startDate.value)
|
||||
startDateText.value = siteDateStatistics(new Date(startDate.value));
|
||||
if (startDate.value) startDateText.value = siteDateStatistics(new Date(startDate.value));
|
||||
}, 1000);
|
||||
});
|
||||
|
||||
@ -94,10 +66,33 @@ onBeforeUnmount(() => {
|
||||
margin-right: 6px;
|
||||
}
|
||||
}
|
||||
.text {
|
||||
display: block;
|
||||
.all-capsule {
|
||||
.capsule-item {
|
||||
margin-bottom: 1rem;
|
||||
.item-title {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin: 1rem 0rem 0.5rem 0rem;
|
||||
font-size: 0.95rem;
|
||||
.remaining {
|
||||
opacity: 0.6;
|
||||
font-size: 0.85rem;
|
||||
font-style: oblique;
|
||||
}
|
||||
}
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
&.start {
|
||||
.item-title {
|
||||
justify-content: center;
|
||||
opacity: 0.8;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -38,55 +38,60 @@ const weatherData = reactive({
|
||||
},
|
||||
});
|
||||
|
||||
// 取出天气平均值
|
||||
const getTemperature = (min, max) => {
|
||||
try {
|
||||
// 计算平均值并四舍五入
|
||||
const average = (Number(min) + Number(max)) / 2;
|
||||
return Math.round(average);
|
||||
} catch (error) {
|
||||
console.error("计算温度出现错误:", error);
|
||||
return "NaN";
|
||||
}
|
||||
};
|
||||
|
||||
// 获取天气数据
|
||||
const getWeatherData = () => {
|
||||
const getWeatherData = async () => {
|
||||
try {
|
||||
// 获取地理位置信息
|
||||
if (!mainKey) {
|
||||
getOtherWeather()
|
||||
.then((res) => {
|
||||
console.log(res);
|
||||
const data = res.result;
|
||||
console.log("未配置,使用备用天气接口");
|
||||
const result = await getOtherWeather();
|
||||
console.log(result);
|
||||
const data = result.result;
|
||||
weatherData.adCode = {
|
||||
city: data.city.name,
|
||||
adcode: data.city.cityId,
|
||||
city: data.city.City || "未知地区",
|
||||
// adcode: data.city.cityId,
|
||||
};
|
||||
weatherData.weather = {
|
||||
weather: data.condition.condition,
|
||||
temperature: data.condition.temp,
|
||||
winddirection: data.condition.windDir,
|
||||
windpower: data.condition.windLevel,
|
||||
weather: data.condition.day_weather,
|
||||
temperature: getTemperature(data.condition.min_degree, data.condition.max_degree),
|
||||
winddirection: data.condition.day_wind_direction,
|
||||
windpower: data.condition.day_wind_power,
|
||||
};
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error("天气信息获取失败:" + err);
|
||||
onError("天气信息获取失败");
|
||||
});
|
||||
} else {
|
||||
getAdcode(mainKey)
|
||||
.then((res) => {
|
||||
// 获取 Adcode
|
||||
const adCode = await getAdcode(mainKey);
|
||||
console.log(adCode);
|
||||
if (adCode.infocode !== "10000") {
|
||||
throw "地区查询失败";
|
||||
}
|
||||
weatherData.adCode = {
|
||||
city: res.city,
|
||||
adcode: res.adcode,
|
||||
city: adCode.city,
|
||||
adcode: adCode.adcode,
|
||||
};
|
||||
// 获取天气信息
|
||||
getWeather(mainKey, weatherData.adCode.adcode)
|
||||
.then((res) => {
|
||||
const result = await getWeather(mainKey, weatherData.adCode.adcode);
|
||||
weatherData.weather = {
|
||||
weather: res.lives[0].weather,
|
||||
temperature: res.lives[0].temperature,
|
||||
winddirection: res.lives[0].winddirection,
|
||||
windpower: res.lives[0].windpower,
|
||||
weather: result.lives[0].weather,
|
||||
temperature: result.lives[0].temperature,
|
||||
winddirection: result.lives[0].winddirection,
|
||||
windpower: result.lives[0].windpower,
|
||||
};
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error("天气信息获取失败:" + err);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("天气信息获取失败:" + error);
|
||||
onError("天气信息获取失败");
|
||||
});
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error("地理位置获取失败:" + err);
|
||||
onError("地理位置获取失败");
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
22
src/main.js
22
src/main.js
@ -1,24 +1,22 @@
|
||||
import {
|
||||
createApp
|
||||
} from 'vue';
|
||||
import '@/style/style.scss';
|
||||
import App from '@/App.vue';
|
||||
import { createApp } from "vue";
|
||||
import "@/style/style.scss";
|
||||
import App from "@/App.vue";
|
||||
// 引入 pinia
|
||||
import {
|
||||
createPinia
|
||||
} from 'pinia';
|
||||
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate';
|
||||
import { createPinia } from "pinia";
|
||||
import piniaPluginPersistedstate from "pinia-plugin-persistedstate";
|
||||
// swiper
|
||||
import "swiper/css";
|
||||
|
||||
const app = createApp(App);
|
||||
const pinia = createPinia();
|
||||
pinia.use(piniaPluginPersistedstate);
|
||||
|
||||
app.use(pinia);
|
||||
app.mount('#app')
|
||||
app.mount("#app");
|
||||
|
||||
// PWA
|
||||
navigator.serviceWorker.addEventListener('controllerchange', () => {
|
||||
navigator.serviceWorker.addEventListener("controllerchange", () => {
|
||||
// 弹出更新提醒
|
||||
console.log("站点已更新,刷新后生效");
|
||||
ElMessage("站点已更新,刷新后生效");
|
||||
})
|
||||
});
|
||||
|
@ -22,6 +22,9 @@ export const mainStore = defineStore("main", {
|
||||
playerLrc: "歌词加载中", // 当前播放歌词
|
||||
playerLrcShow: true, // 是否显示底栏歌词
|
||||
footerBlur: true, // 底栏模糊
|
||||
playerAutoplay: false, // 是否自动播放
|
||||
playerLoop: "all", // 循环播放 "all", "one", "none"
|
||||
playerOrder: "list", // 循环顺序 "list", "random"
|
||||
};
|
||||
},
|
||||
getters: {
|
||||
@ -82,6 +85,9 @@ export const mainStore = defineStore("main", {
|
||||
"musicClick",
|
||||
"playerLrcShow",
|
||||
"footerBlur",
|
||||
"playerAutoplay",
|
||||
"playerLoop",
|
||||
"playerOrder",
|
||||
],
|
||||
},
|
||||
});
|
||||
|
@ -1,7 +1,7 @@
|
||||
// scss 全局变量
|
||||
|
||||
// 响应式布局
|
||||
@mixin changeWidth($maxWidth:1200px) {
|
||||
@mixin changeWidth($maxWidth: 1200px) {
|
||||
.container {
|
||||
max-width: $maxWidth;
|
||||
}
|
||||
@ -19,17 +19,16 @@
|
||||
|
||||
/* 小于1280px时 */
|
||||
@media (max-width: 1280px) {
|
||||
@include changeWidth($maxWidth:1100px);
|
||||
@include changeWidth($maxWidth: 1100px);
|
||||
}
|
||||
|
||||
/* 小于992px时 */
|
||||
@media (max-width: 992px) {
|
||||
@include changeWidth($maxWidth:900px);
|
||||
@include changeWidth($maxWidth: 900px);
|
||||
}
|
||||
|
||||
/* 小于720px时 */
|
||||
@media (max-width: 720px) {
|
||||
|
||||
// 隐藏元素
|
||||
.xs-hidden {
|
||||
display: none;
|
||||
|
@ -13,6 +13,8 @@ html,
|
||||
body {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
// width: 100dvh;
|
||||
// height: 100dvh;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
background-color: #333;
|
||||
@ -38,11 +40,13 @@ p {
|
||||
// 字体文件
|
||||
@font-face {
|
||||
font-family: "Pacifico-Regular";
|
||||
font-display: swap;
|
||||
src: url("/font/Pacifico-Regular.ttf") format("truetype");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "UnidreamLED";
|
||||
font-display: swap;
|
||||
src: url("/font/UnidreamLED.ttf") format("truetype");
|
||||
}
|
||||
|
||||
@ -51,8 +55,8 @@ p {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
@ -62,7 +66,9 @@ p {
|
||||
background-color: #00000040;
|
||||
backdrop-filter: blur(10px);
|
||||
transform: scale(1);
|
||||
transition: backdrop-filter 0.3s, transform 0.3s;
|
||||
transition:
|
||||
backdrop-filter 0.3s,
|
||||
transform 0.3s;
|
||||
&:hover {
|
||||
transform: scale(1.01);
|
||||
}
|
||||
@ -164,7 +170,7 @@ p {
|
||||
}
|
||||
to {
|
||||
filter: blur(0) brightness(1);
|
||||
transform: scale(1.2);
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,21 +1,26 @@
|
||||
var CURSOR;
|
||||
let mainCursor;
|
||||
|
||||
Math.lerp = (a, b, n) => (1 - n) * a + n * b;
|
||||
|
||||
const getStyle = (el, attr) => {
|
||||
try {
|
||||
return window.getComputedStyle ?
|
||||
window.getComputedStyle(el)[attr] :
|
||||
el.currentStyle[attr];
|
||||
} catch (e) {}
|
||||
return "";
|
||||
return window.getComputedStyle ? window.getComputedStyle(el)[attr] : el.currentStyle[attr];
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
const cursorInit = () => {
|
||||
mainCursor = new Cursor();
|
||||
return mainCursor;
|
||||
};
|
||||
|
||||
class Cursor {
|
||||
constructor() {
|
||||
this.pos = {
|
||||
curr: null,
|
||||
prev: null
|
||||
prev: null,
|
||||
};
|
||||
this.pt = [];
|
||||
this.create();
|
||||
@ -37,10 +42,9 @@ class Cursor {
|
||||
document.body.append(this.cursor);
|
||||
}
|
||||
|
||||
var el = document.getElementsByTagName('*');
|
||||
var el = document.getElementsByTagName("*");
|
||||
for (let i = 0; i < el.length; i++)
|
||||
if (getStyle(el[i], "cursor") == "pointer")
|
||||
this.pt.push(el[i].outerHTML);
|
||||
if (getStyle(el[i], "cursor") == "pointer") this.pt.push(el[i].outerHTML);
|
||||
|
||||
document.body.appendChild((this.scr = document.createElement("style")));
|
||||
this.scr.innerHTML = `* {cursor: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8' width='10px' height='10px'><circle cx='4' cy='4' r='4' fill='white' /></svg>") 4 4, auto !important}`;
|
||||
@ -51,7 +55,7 @@ class Cursor {
|
||||
this.cursor.classList.remove("active");
|
||||
this.pos = {
|
||||
curr: null,
|
||||
prev: null
|
||||
prev: null,
|
||||
};
|
||||
this.pt = [];
|
||||
|
||||
@ -61,18 +65,18 @@ class Cursor {
|
||||
}
|
||||
|
||||
init() {
|
||||
document.onmousemove = e => {
|
||||
(this.pos.curr == null) && this.move(e.clientX - 8, e.clientY - 8);
|
||||
document.onmousemove = (e) => {
|
||||
this.pos.curr == null && this.move(e.clientX - 8, e.clientY - 8);
|
||||
this.pos.curr = {
|
||||
x: e.clientX - 8,
|
||||
y: e.clientY - 8
|
||||
y: e.clientY - 8,
|
||||
};
|
||||
this.cursor.classList.remove("hidden");
|
||||
};
|
||||
document.onmouseenter = e => this.cursor.classList.remove("hidden");
|
||||
document.onmouseleave = e => this.cursor.classList.add("hidden");
|
||||
document.onmousedown = e => this.cursor.classList.add("active");
|
||||
document.onmouseup = e => this.cursor.classList.remove("active");
|
||||
document.onmouseenter = () => this.cursor.classList.remove("hidden");
|
||||
document.onmouseleave = () => this.cursor.classList.add("hidden");
|
||||
document.onmousedown = () => this.cursor.classList.add("active");
|
||||
document.onmouseup = () => this.cursor.classList.remove("active");
|
||||
}
|
||||
|
||||
render() {
|
||||
@ -87,8 +91,4 @@ class Cursor {
|
||||
}
|
||||
}
|
||||
|
||||
const cursorInit = () => {
|
||||
CURSOR = new Cursor();
|
||||
};
|
||||
|
||||
export default cursorInit;
|
@ -12,10 +12,10 @@ function debounce(func, wait = 300, immediate = false) {
|
||||
timeout = setTimeout(function () {
|
||||
timeout = null;
|
||||
}, wait);
|
||||
if (callNow) typeof func === 'function' && func();
|
||||
if (callNow) typeof func === "function" && func();
|
||||
} else {
|
||||
timeout = setTimeout(function () {
|
||||
typeof func === 'function' && func();
|
||||
typeof func === "function" && func();
|
||||
}, wait);
|
||||
}
|
||||
}
|
||||
|
@ -1,29 +1,17 @@
|
||||
import { h } from "vue";
|
||||
import { SpaCandle } from "@icon-park/vue-next";
|
||||
import dayjs from "dayjs";
|
||||
|
||||
// 时钟
|
||||
export const getCurrentTime = () => {
|
||||
let time = new Date();
|
||||
let year = time.getFullYear();
|
||||
let month =
|
||||
time.getMonth() + 1 < 10
|
||||
? "0" + (time.getMonth() + 1)
|
||||
: time.getMonth() + 1;
|
||||
let month = time.getMonth() + 1 < 10 ? "0" + (time.getMonth() + 1) : time.getMonth() + 1;
|
||||
let day = time.getDate() < 10 ? "0" + time.getDate() : time.getDate();
|
||||
let hour = time.getHours() < 10 ? "0" + time.getHours() : time.getHours();
|
||||
let minute =
|
||||
time.getMinutes() < 10 ? "0" + time.getMinutes() : time.getMinutes();
|
||||
let second =
|
||||
time.getSeconds() < 10 ? "0" + time.getSeconds() : time.getSeconds();
|
||||
let weekday = [
|
||||
"星期日",
|
||||
"星期一",
|
||||
"星期二",
|
||||
"星期三",
|
||||
"星期四",
|
||||
"星期五",
|
||||
"星期六",
|
||||
];
|
||||
let minute = time.getMinutes() < 10 ? "0" + time.getMinutes() : time.getMinutes();
|
||||
let second = time.getSeconds() < 10 ? "0" + time.getSeconds() : time.getSeconds();
|
||||
let weekday = ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"];
|
||||
let currentTime = {
|
||||
year,
|
||||
month,
|
||||
@ -38,47 +26,48 @@ export const getCurrentTime = () => {
|
||||
|
||||
// 时光胶囊
|
||||
export const getTimeCapsule = () => {
|
||||
// 日进度
|
||||
const todayStartDate = new Date(new Date().toLocaleDateString()).getTime();
|
||||
const todayPassHours = (new Date() - todayStartDate) / 1000 / 60 / 60;
|
||||
const todayPassHoursPercent = (todayPassHours / 24) * 100;
|
||||
|
||||
// 周进度
|
||||
const weeks = [7, 1, 2, 3, 4, 5, 6];
|
||||
const weekDay = weeks[new Date().getDay()];
|
||||
const weekDayPassPercent = (weekDay / 7) * 100;
|
||||
|
||||
// 月进度
|
||||
const year = new Date().getFullYear();
|
||||
const date = new Date().getDate();
|
||||
const month = new Date().getMonth() + 1;
|
||||
const monthAll = new Date(year, month, 0).getDate();
|
||||
const monthPassPercent = (date / monthAll) * 100;
|
||||
|
||||
// 年进度
|
||||
const yearStartDate = new Date(year, 0, 1).getTime();
|
||||
const yearEndDate = new Date(year + 1, 0, 1).getTime();
|
||||
const yearPassHours = (new Date() - yearStartDate) / 1000 / 60 / 60;
|
||||
const yearTotalHours = (yearEndDate - yearStartDate) / 1000 / 60 / 60;
|
||||
const yearPassPercent = (yearPassHours / yearTotalHours) * 100;
|
||||
|
||||
const now = dayjs();
|
||||
const dayText = {
|
||||
day: "今日",
|
||||
week: "本周",
|
||||
month: "本月",
|
||||
year: "本年",
|
||||
};
|
||||
/**
|
||||
* 计算时间差的函数
|
||||
* @param {String} unit 时间单位,可以是 'day', 'week', 'month', 'year'
|
||||
*/
|
||||
const getDifference = (unit) => {
|
||||
// 获取当前时间单位的开始时间
|
||||
const start = now.startOf(unit);
|
||||
// 获取当前时间单位的结束时间
|
||||
const end = now.endOf(unit);
|
||||
// 计算总的天数或小时数
|
||||
const total = end.diff(start, unit === "day" ? "hour" : "day") + 1;
|
||||
// 计算已经过去的天数或小时数
|
||||
let passed;
|
||||
if (unit === "week" && now.day() === 0) {
|
||||
// 如果是星期日
|
||||
passed = total - 1;
|
||||
} else {
|
||||
passed = now.diff(start, unit === "day" ? "hour" : "day");
|
||||
}
|
||||
const remaining = total - passed;
|
||||
const percentage = (passed / total) * 100;
|
||||
// 返回数据
|
||||
return {
|
||||
day: {
|
||||
elapsed: Math.floor(todayPassHours),
|
||||
pass: Math.floor(todayPassHoursPercent),
|
||||
},
|
||||
week: {
|
||||
elapsed: weekDay,
|
||||
pass: Math.floor(weekDayPassPercent),
|
||||
},
|
||||
month: {
|
||||
elapsed: date,
|
||||
pass: Math.floor(monthPassPercent),
|
||||
},
|
||||
year: {
|
||||
elapsed: month - 1,
|
||||
pass: Math.floor(yearPassPercent),
|
||||
},
|
||||
name: dayText[unit],
|
||||
total: total,
|
||||
passed: passed,
|
||||
remaining: remaining,
|
||||
percentage: percentage.toFixed(2),
|
||||
};
|
||||
};
|
||||
return {
|
||||
day: getDifference("day"),
|
||||
week: getDifference("week"),
|
||||
month: getDifference("month"),
|
||||
year: getDifference("year"),
|
||||
};
|
||||
};
|
||||
|
||||
@ -122,7 +111,7 @@ export const checkDays = () => {
|
||||
const mon = myDate.getMonth() + 1;
|
||||
const date = myDate.getDate();
|
||||
const key = `${mon}.${date}`;
|
||||
if (anniversaries.hasOwnProperty(key)) {
|
||||
if (Object.prototype.hasOwnProperty.call(anniversaries, key)) {
|
||||
console.log(`今天是${anniversaries[key]}`);
|
||||
const gray = document.createElement("style");
|
||||
gray.innerHTML = "html{filter: grayscale(100%)}";
|
||||
@ -144,11 +133,11 @@ export const siteDateStatistics = (startDate) => {
|
||||
const differenceInYears = differenceInMonths / 12;
|
||||
if (differenceInYears >= 1) {
|
||||
return `本站已经苟活了 ${Math.floor(differenceInYears)} 年 ${Math.floor(
|
||||
differenceInMonths % 12
|
||||
differenceInMonths % 12,
|
||||
)} 月 ${Math.round(differenceInDays % 30)} 天`;
|
||||
} else if (differenceInMonths >= 1) {
|
||||
return `本站已经苟活了 ${Math.floor(differenceInMonths)} 月 ${Math.round(
|
||||
differenceInDays % 30
|
||||
differenceInDays % 30,
|
||||
)} 天`;
|
||||
} else {
|
||||
return `本站已经苟活了 ${Math.round(differenceInDays)} 天`;
|
||||
|
@ -1,9 +1,5 @@
|
||||
<template>
|
||||
<div
|
||||
class="box cards"
|
||||
@mouseenter="closeShow = true"
|
||||
@mouseleave="closeShow = false"
|
||||
>
|
||||
<div class="box cards" @mouseenter="closeShow = true" @mouseleave="closeShow = false">
|
||||
<transition name="el-fade-in-linear">
|
||||
<close-one
|
||||
class="close"
|
||||
@ -25,7 +21,9 @@
|
||||
/>
|
||||
</transition>
|
||||
<div class="content">
|
||||
<!-- 可在此处自定义任意内容 -->
|
||||
<TimeCapsule />
|
||||
<MoreContent />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@ -34,6 +32,7 @@
|
||||
import { CloseOne, SettingTwo } from "@icon-park/vue-next";
|
||||
import { mainStore } from "@/store";
|
||||
import TimeCapsule from "@/components/TimeCapsule.vue";
|
||||
import MoreContent from "@/components/MoreContent.vue";
|
||||
|
||||
const store = mainStore();
|
||||
const closeShow = ref(false);
|
||||
@ -44,6 +43,7 @@ const closeShow = ref(false);
|
||||
flex: 1 0 0%;
|
||||
margin-left: 0.75rem;
|
||||
height: 80%;
|
||||
max-width: 50%;
|
||||
position: relative;
|
||||
animation: fade 0.5s;
|
||||
|
||||
@ -58,7 +58,9 @@ const closeShow = ref(false);
|
||||
right: 14px;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
transition: transform 0.3s, opacity 0.3s;
|
||||
transition:
|
||||
transform 0.3s,
|
||||
opacity 0.3s;
|
||||
|
||||
&:hover {
|
||||
transform: scale(1.2);
|
||||
@ -74,6 +76,8 @@ const closeShow = ref(false);
|
||||
}
|
||||
|
||||
.content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 30px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
@ -5,7 +5,7 @@
|
||||
<el-col :span="12">
|
||||
<div class="left">
|
||||
<Hitokoto />
|
||||
<Music />
|
||||
<Music v-if="playerHasId" />
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
@ -18,11 +18,7 @@
|
||||
<span class="sm-hidden">{{ currentTime.weekday }}</span>
|
||||
</div>
|
||||
<div class="text">
|
||||
<span>
|
||||
{{ currentTime.hour }}:{{ currentTime.minute }}:{{
|
||||
currentTime.second
|
||||
}}</span
|
||||
>
|
||||
<span> {{ currentTime.hour }}:{{ currentTime.minute }}:{{ currentTime.second }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<Weather />
|
||||
@ -45,6 +41,9 @@ const store = mainStore();
|
||||
const currentTime = ref({});
|
||||
const timeInterval = ref(null);
|
||||
|
||||
// 播放器 id
|
||||
const playerHasId = import.meta.env.VITE_SONG_ID;
|
||||
|
||||
// 更新时间
|
||||
const updateTimeData = () => {
|
||||
currentTime.value = getCurrentTime();
|
||||
|
@ -19,10 +19,18 @@ import Link from "@/components/Links.vue";
|
||||
const store = mainStore();
|
||||
|
||||
// 站点链接
|
||||
const siteUrl = import.meta.env.VITE_SITE_URL.split(".");
|
||||
const siteUrl = computed(() => {
|
||||
const url = import.meta.env.VITE_SITE_URL;
|
||||
if (!url) return "imsyy.top".split(".");
|
||||
// 判断协议前缀
|
||||
if (url.startsWith("http://") || url.startsWith("https://")) {
|
||||
const urlFormat = url.replace(/^(https?:\/\/)/, "");
|
||||
return urlFormat.split(".");
|
||||
}
|
||||
return url.split(".");
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.right {
|
||||
// flex: 1 0 0%;
|
||||
|
@ -1,10 +1,5 @@
|
||||
<template>
|
||||
<div
|
||||
class="set"
|
||||
@mouseenter="closeShow = true"
|
||||
@mouseleave="closeShow = false"
|
||||
@click.stop
|
||||
>
|
||||
<div class="set" @mouseenter="closeShow = true" @mouseleave="closeShow = false" @click.stop>
|
||||
<transition name="el-fade-in-linear">
|
||||
<close-one
|
||||
class="close"
|
||||
@ -23,17 +18,8 @@
|
||||
</div>
|
||||
<div class="version">
|
||||
<div class="num">v {{ config.version }}</div>
|
||||
<el-tooltip
|
||||
content="Github 源代码仓库"
|
||||
placement="right"
|
||||
:show-arrow="false"
|
||||
>
|
||||
<github-one
|
||||
class="github"
|
||||
theme="outline"
|
||||
size="24"
|
||||
@click="jumpTo(config.github)"
|
||||
/>
|
||||
<el-tooltip content="Github 源代码仓库" placement="right" :show-arrow="false">
|
||||
<github-one class="github" theme="outline" size="24" @click="jumpTo(config.github)" />
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<el-card class="update">
|
||||
@ -66,13 +52,7 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {
|
||||
CloseOne,
|
||||
SettingTwo,
|
||||
GithubOne,
|
||||
AddOne,
|
||||
Bug,
|
||||
} from "@icon-park/vue-next";
|
||||
import { CloseOne, SettingTwo, GithubOne, AddOne, Bug } from "@icon-park/vue-next";
|
||||
import { mainStore } from "@/store";
|
||||
import Set from "@/components/Set.vue";
|
||||
import config from "@/../package.json";
|
||||
@ -81,7 +61,16 @@ const store = mainStore();
|
||||
const closeShow = ref(false);
|
||||
|
||||
// 站点链接
|
||||
const siteUrl = import.meta.env.VITE_SITE_URL.split(".");
|
||||
const siteUrl = computed(() => {
|
||||
const url = import.meta.env.VITE_SITE_URL;
|
||||
if (!url) return "imsyy.top".split(".");
|
||||
// 判断协议前缀
|
||||
if (url.startsWith("http://") || url.startsWith("https://")) {
|
||||
const urlFormat = url.replace(/^(https?:\/\/)/, "");
|
||||
return urlFormat.split(".");
|
||||
}
|
||||
return url.split(".");
|
||||
});
|
||||
|
||||
// 更新日志
|
||||
const upData = reactive({
|
||||
@ -91,12 +80,7 @@ const upData = reactive({
|
||||
"壁纸支持个性化设置",
|
||||
"音乐播放器支持音量控制",
|
||||
],
|
||||
fix: [
|
||||
"修复天气 API",
|
||||
"时光胶囊显示错误",
|
||||
"移动端动画及细节",
|
||||
"图标更换为 IconPark",
|
||||
],
|
||||
fix: ["修复天气 API", "时光胶囊显示错误", "移动端动画及细节", "图标更换为 IconPark"],
|
||||
});
|
||||
|
||||
// 跳转源代码仓库
|
||||
@ -149,10 +133,10 @@ const jumpTo = (url) => {
|
||||
.logo {
|
||||
transform: translateY(-8%);
|
||||
font-family: "Pacifico-Regular";
|
||||
// line-height: 5rem;
|
||||
padding-left: 22px;
|
||||
width: 100%;
|
||||
height: 260px;
|
||||
|
||||
min-height: 140px;
|
||||
.bg {
|
||||
font-size: 5rem;
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
/* eslint-disable no-undef */
|
||||
import { defineConfig, loadEnv } from "vite";
|
||||
import { ElementPlusResolver } from "unplugin-vue-components/resolvers";
|
||||
import { resolve } from "path";
|
||||
|
Loading…
Reference in New Issue
Block a user