Compare commits
226 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 | ||
![]() |
231c5b6cea | ||
![]() |
c12ddfb6b4 | ||
![]() |
fe10751062 | ||
![]() |
2496110d5d | ||
![]() |
d87d467dc7 | ||
![]() |
c5b0b44fed | ||
![]() |
a422495c5f | ||
![]() |
65d1345169 | ||
![]() |
b9f9e5d527 | ||
![]() |
9d2290d694 | ||
![]() |
7048a134be | ||
![]() |
12808714c1 | ||
![]() |
21914f8937 | ||
![]() |
ff83ffd53a | ||
![]() |
177b539e39 | ||
![]() |
acc8f54ef9 | ||
![]() |
db0d3b92ae | ||
![]() |
ab931acfb6 | ||
![]() |
faeb0b98fc | ||
![]() |
7adf606935 | ||
![]() |
5c9e14a585 | ||
![]() |
03eef44392 | ||
![]() |
ddda08c037 | ||
![]() |
8f46b8dd46 | ||
![]() |
82a6877681 | ||
![]() |
05eb444ccf | ||
![]() |
15adc605a2 | ||
![]() |
cee5a05de0 | ||
![]() |
fe89288f50 | ||
![]() |
7b7c793e1b | ||
![]() |
0c4a85b458 | ||
![]() |
854cebff03 | ||
![]() |
ff18b63416 | ||
![]() |
50023ea536 | ||
![]() |
47fd9d3ee8 | ||
![]() |
436b7281df | ||
![]() |
09165d971a | ||
![]() |
b5ab4ac07c | ||
![]() |
50adca44e8 | ||
![]() |
c4c040402b | ||
![]() |
d3248d2fd9 | ||
![]() |
b8ed0c1926 | ||
![]() |
65d24f05d1 | ||
![]() |
041daf4c22 | ||
![]() |
431f3732f6 | ||
![]() |
97007b05c1 | ||
![]() |
4c63155ada | ||
![]() |
d5fc31ee83 | ||
![]() |
bd2b1a903d | ||
![]() |
4b5aaa8705 | ||
![]() |
9ca1237f24 | ||
![]() |
489a55ce1f | ||
![]() |
cb5650396c | ||
![]() |
8c230537ce | ||
![]() |
a5461c39aa | ||
![]() |
3c5557654b | ||
![]() |
00a91bbb36 | ||
![]() |
6103cafb36 | ||
![]() |
5b15716092 | ||
![]() |
abcfa92d8b | ||
![]() |
e5310257ed | ||
![]() |
5090ce2e89 | ||
![]() |
021e3c0bbe | ||
![]() |
4ce5492139 | ||
![]() |
e7beed15cd | ||
![]() |
6e416bfec0 | ||
![]() |
9da5e50040 | ||
![]() |
3463084339 | ||
![]() |
8c6dc91075 | ||
![]() |
48afe35097 | ||
![]() |
0e32dd4113 | ||
![]() |
9bf33c5610 | ||
![]() |
700b53e79d | ||
![]() |
af659fe259 | ||
![]() |
a7348a1893 | ||
![]() |
311f30e4f0 | ||
![]() |
c0e460f1a8 | ||
![]() |
ed11a572c9 | ||
![]() |
b4d0e55e8f | ||
![]() |
005b7cb886 | ||
![]() |
d22c329264 | ||
![]() |
c3b0dcd6cf | ||
![]() |
e3ea1e7364 | ||
![]() |
fa99da9260 | ||
![]() |
92bcd4e73f | ||
![]() |
ec54393a93 | ||
![]() |
5eda25c75e | ||
![]() |
5e2fcd656a | ||
![]() |
0af8f0ec2e | ||
![]() |
7803016119 | ||
![]() |
d95b2708c3 | ||
![]() |
0f71818829 | ||
![]() |
966580e3d8 | ||
![]() |
3489249f61 | ||
![]() |
1eab49d8bb | ||
![]() |
cdf644caba | ||
![]() |
4b570d3f98 | ||
![]() |
2604d143e6 | ||
![]() |
ab5b3f317e | ||
![]() |
829dee9451 | ||
![]() |
eaf640bfd8 | ||
![]() |
f03616018f | ||
![]() |
ee349baa25 | ||
![]() |
9805f64da6 | ||
![]() |
9d7f369f61 | ||
![]() |
80a41ec182 | ||
![]() |
ca1b3dc00b | ||
![]() |
20e8d972e3 | ||
![]() |
34e9007870 | ||
![]() |
c306b60eab | ||
![]() |
042231c094 | ||
![]() |
9c141815f5 | ||
![]() |
d063784d73 | ||
![]() |
5f79695cef | ||
![]() |
30c55aaa29 | ||
![]() |
3d0ae1d6e1 | ||
![]() |
6f18cc9193 | ||
![]() |
43e4f32aec | ||
![]() |
cba6a1587f | ||
![]() |
2cf00823fe | ||
![]() |
48978b467f | ||
![]() |
f82aef306c | ||
![]() |
49fb4b49d5 | ||
![]() |
bd4ad30524 | ||
![]() |
dbdf84c352 | ||
![]() |
1ac1c05022 | ||
![]() |
bee5fe6465 | ||
![]() |
6a5920ce3f | ||
![]() |
0fc2ad45a4 | ||
![]() |
427c9ff678 | ||
![]() |
141fed8583 | ||
![]() |
2f5aea8d6e | ||
![]() |
96cbc413df | ||
![]() |
12bceb4c83 | ||
![]() |
b1ea5e3aba | ||
![]() |
3817e6e43d | ||
![]() |
d07179342c | ||
![]() |
1c9441e606 | ||
![]() |
1671006805 | ||
![]() |
bd9531044f | ||
![]() |
26d12e33a7 | ||
![]() |
f9cc6c73eb | ||
![]() |
5c3d5cdeb0 | ||
![]() |
9b0a355ae1 | ||
![]() |
b9a9a126e0 | ||
![]() |
9cf78b28db | ||
![]() |
3f649c4369 | ||
![]() |
35c6d60a35 | ||
![]() |
ec5f157f2a | ||
![]() |
35aebf1061 | ||
![]() |
6e6fa9d7e4 | ||
![]() |
c73da0a4ac | ||
![]() |
ec133f786b | ||
![]() |
5722d17f43 | ||
![]() |
7ff8f34dbd | ||
![]() |
06bf60ad49 | ||
![]() |
f93e064b67 | ||
![]() |
0e711ecd88 | ||
![]() |
34b48250bf | ||
![]() |
f6d50e2093 | ||
![]() |
758d3b9958 | ||
![]() |
4a35a0f1d9 | ||
![]() |
f8a88ad4ce | ||
![]() |
42723f01a0 | ||
![]() |
b8c3c871aa | ||
![]() |
bf587526bd | ||
![]() |
4c49b61be0 | ||
![]() |
04296fd05e | ||
![]() |
917517c1b0 | ||
![]() |
e01e943353 | ||
![]() |
2d8b8e8b80 | ||
![]() |
6f47dbbe56 | ||
![]() |
0c973a3622 | ||
![]() |
c95b5e6691 | ||
![]() |
5085e9ea1b | ||
![]() |
29e36c3401 | ||
![]() |
5cc3847c7c | ||
![]() |
cfae7cc61b | ||
![]() |
2a6eabac95 | ||
![]() |
99e2d68e5e | ||
![]() |
0579e3b0e9 | ||
![]() |
46ddf457a7 | ||
![]() |
e1151a35e6 | ||
![]() |
ecaec186d2 | ||
![]() |
da00c86790 |
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
|
51
.env.example
Normal file
@ -0,0 +1,51 @@
|
||||
# 站点信息
|
||||
VITE_SITE_NAME = "無名の主页" # 名称
|
||||
VITE_SITE_ANTHOR = "無名" # 作者
|
||||
VITE_SITE_KEYWORDS = "無名,个人主页" # 关键词
|
||||
VITE_SITE_DES = "一个默默无闻的主页" # 站点简介
|
||||
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 端图标
|
||||
|
||||
# 简介文本
|
||||
VITE_DESC_HELLO = "Hello World !"
|
||||
VITE_DESC_TEXT = "一个建立于 21 世纪的小站,存活于互联网的边缘"
|
||||
VITE_DESC_HELLO_OTHER = "Oops !"
|
||||
VITE_DESC_TEXT_OTHER = "哎呀,这都被你发现了( 再点击一次可关闭 )"
|
||||
|
||||
# 社交链接
|
||||
## 请在 src/assets/socialLinks.json 文件中配置
|
||||
|
||||
# 网站链接
|
||||
## 请在 src/assets/siteLinks.json 文件中配置
|
||||
## 网站链接的图标名称可前往 https://www.xicons.org 自行挑选并在 src/components/Links/index.vue 中引入
|
||||
|
||||
# 天气 Key
|
||||
## 请前往 高德开放平台注册 Web服务 Key
|
||||
## 请注意不是 Web端 (JS API),免费申请,每日上限 5000 次
|
||||
## 此处提供的服务可能会超量从而无法访问,请自行申请!请自行申请!请自行申请!
|
||||
## 若此处设为空则调用 教书先生 API https://api.oioweb.cn/doc/weather/GetWeather
|
||||
VITE_WEATHER_KEY = ""
|
||||
|
||||
# 建站日期
|
||||
## 若不需要,请设为空即可
|
||||
## 请按照 YYYY-MM-DD 格式填写或者仅填写年份 YYYY
|
||||
VITE_SITE_START = "2020-10-24"
|
||||
|
||||
# ICP 备案号
|
||||
## 若不需要,请设为空即可
|
||||
VITE_SITE_ICP = "豫ICP备2022018134号-1"
|
||||
|
||||
# 歌曲 API 地址
|
||||
## 请参照 https://github.com/xizeyoupan/Meting-API#deno-deploy 进行 API 服务部署
|
||||
## 此处提供的服务可能会超量从而无法访问,请自行部署
|
||||
## 若使用 QQ 音乐歌单,歌曲数量最好不要超出 50 首
|
||||
## 备用:https://api.wuenci.com/meting/api/
|
||||
VITE_SONG_API = "https://api-meting.imsyy.top/api"
|
||||
# 歌曲服务器 ( netease-网易云, tencent-qq音乐 )
|
||||
VITE_SONG_SERVER = "netease"
|
||||
# 播放类型 ( song-歌曲, playlist-播放列表, album-专辑, search-搜索, artist-艺术家 )
|
||||
VITE_SONG_TYPE = "playlist"
|
||||
# 播放 ID ( 若无需播放器,请设为空即可 )
|
||||
VITE_SONG_ID = "9379831714"
|
3
.eslintignore
Normal file
@ -0,0 +1,3 @@
|
||||
node_modules
|
||||
dist
|
||||
.gitignore
|
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
|
||||
}
|
||||
}
|
22
.github/ISSUE_TEMPLATE/bug-en.yml
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
name: Encountering an Issue
|
||||
description: Please provide details about the issue you are encountering
|
||||
labels: [bug]
|
||||
body:
|
||||
- type: input
|
||||
id: site-url
|
||||
validations:
|
||||
required: true
|
||||
attributes:
|
||||
label: "Site URL"
|
||||
placeholder: "Please provide the URL of the site where the issue occurred"
|
||||
- type: input
|
||||
id: problem
|
||||
attributes:
|
||||
label: "Description of the Issue"
|
||||
description: "Include any error messages or screenshots if applicable"
|
||||
placeholder: "Please describe the issue you are encountering"
|
||||
- type: textarea
|
||||
id: other
|
||||
attributes:
|
||||
label: "Additional Information"
|
||||
description: "Is there anything else you would like to add?"
|
22
.github/ISSUE_TEMPLATE/bug.yml
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
name: 遇到问题
|
||||
description: 请填写遇到的问题的详细信息
|
||||
labels: [bug]
|
||||
body:
|
||||
- type: input
|
||||
id: site-url
|
||||
validations:
|
||||
required: true
|
||||
attributes:
|
||||
label: "站点链接"
|
||||
placeholder: "请填写你的站点链接"
|
||||
- type: input
|
||||
id: problem
|
||||
attributes:
|
||||
label: "问题描述"
|
||||
description: "有错误的话请提供报错截图"
|
||||
placeholder: "请详细描述一下遇到的问题"
|
||||
- type: textarea
|
||||
id: other
|
||||
attributes:
|
||||
label: "补充信息"
|
||||
description: "还需要说些什么吗"
|
14
.github/ISSUE_TEMPLATE/other-en.yml
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
name: Other Information
|
||||
description: Any other issues or questions related to usage
|
||||
labels: [other]
|
||||
body:
|
||||
- type: textarea
|
||||
id: title
|
||||
attributes:
|
||||
label: "Description of the Issue"
|
||||
description: "Please provide a clear description of the issue you are experiencing"
|
||||
- type: textarea
|
||||
id: other
|
||||
attributes:
|
||||
label: "Additional Information"
|
||||
description: "Is there any other information you would like to add?"
|
14
.github/ISSUE_TEMPLATE/other.yml
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
name: 其他信息
|
||||
description: 关于使用上的问题
|
||||
labels: [other]
|
||||
body:
|
||||
- type: textarea
|
||||
id: title
|
||||
attributes:
|
||||
label: "问题描述"
|
||||
description: "请尽量清晰的描述您遇到的问题"
|
||||
- type: textarea
|
||||
id: other
|
||||
attributes:
|
||||
label: "补充信息"
|
||||
description: "有需要补充的信息吗"
|
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
|
25
.gitignore
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
.env
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
.DS_Store
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
17
.hintrc
Normal file
@ -0,0 +1,17 @@
|
||||
{
|
||||
"extends": [
|
||||
"development"
|
||||
],
|
||||
"hints": {
|
||||
"compat-api/html": "off",
|
||||
"no-protocol-relative-urls": "off",
|
||||
"compat-api/css": [
|
||||
"default",
|
||||
{
|
||||
"ignore": [
|
||||
"backdrop-filter"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
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
|
||||
}
|
3
.vscode/extensions.json
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"recommendations": ["Vue.volar"]
|
||||
}
|
128
CODE_OF_CONDUCT.md
Normal file
@ -0,0 +1,128 @@
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
We as members, contributors, and leaders pledge to make participation in our
|
||||
community a harassment-free experience for everyone, regardless of age, body
|
||||
size, visible or invisible disability, ethnicity, sex characteristics, gender
|
||||
identity and expression, level of experience, education, socio-economic status,
|
||||
nationality, personal appearance, race, religion, or sexual identity
|
||||
and orientation.
|
||||
|
||||
We pledge to act and interact in ways that contribute to an open, welcoming,
|
||||
diverse, inclusive, and healthy community.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to a positive environment for our
|
||||
community include:
|
||||
|
||||
* Demonstrating empathy and kindness toward other people
|
||||
* Being respectful of differing opinions, viewpoints, and experiences
|
||||
* Giving and gracefully accepting constructive feedback
|
||||
* Accepting responsibility and apologizing to those affected by our mistakes,
|
||||
and learning from the experience
|
||||
* Focusing on what is best not just for us as individuals, but for the
|
||||
overall community
|
||||
|
||||
Examples of unacceptable behavior include:
|
||||
|
||||
* The use of sexualized language or imagery, and sexual attention or
|
||||
advances of any kind
|
||||
* Trolling, insulting or derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or email
|
||||
address, without their explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Enforcement Responsibilities
|
||||
|
||||
Community leaders are responsible for clarifying and enforcing our standards of
|
||||
acceptable behavior and will take appropriate and fair corrective action in
|
||||
response to any behavior that they deem inappropriate, threatening, offensive,
|
||||
or harmful.
|
||||
|
||||
Community leaders have the right and responsibility to remove, edit, or reject
|
||||
comments, commits, code, wiki edits, issues, and other contributions that are
|
||||
not aligned to this Code of Conduct, and will communicate reasons for moderation
|
||||
decisions when appropriate.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies within all community spaces, and also applies when
|
||||
an individual is officially representing the community in public spaces.
|
||||
Examples of representing our community include using an official e-mail address,
|
||||
posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported to the community leaders responsible for enforcement at
|
||||
one@imsyy.top.
|
||||
All complaints will be reviewed and investigated promptly and fairly.
|
||||
|
||||
All community leaders are obligated to respect the privacy and security of the
|
||||
reporter of any incident.
|
||||
|
||||
## Enforcement Guidelines
|
||||
|
||||
Community leaders will follow these Community Impact Guidelines in determining
|
||||
the consequences for any action they deem in violation of this Code of Conduct:
|
||||
|
||||
### 1. Correction
|
||||
|
||||
**Community Impact**: Use of inappropriate language or other behavior deemed
|
||||
unprofessional or unwelcome in the community.
|
||||
|
||||
**Consequence**: A private, written warning from community leaders, providing
|
||||
clarity around the nature of the violation and an explanation of why the
|
||||
behavior was inappropriate. A public apology may be requested.
|
||||
|
||||
### 2. Warning
|
||||
|
||||
**Community Impact**: A violation through a single incident or series
|
||||
of actions.
|
||||
|
||||
**Consequence**: A warning with consequences for continued behavior. No
|
||||
interaction with the people involved, including unsolicited interaction with
|
||||
those enforcing the Code of Conduct, for a specified period of time. This
|
||||
includes avoiding interactions in community spaces as well as external channels
|
||||
like social media. Violating these terms may lead to a temporary or
|
||||
permanent ban.
|
||||
|
||||
### 3. Temporary Ban
|
||||
|
||||
**Community Impact**: A serious violation of community standards, including
|
||||
sustained inappropriate behavior.
|
||||
|
||||
**Consequence**: A temporary ban from any sort of interaction or public
|
||||
communication with the community for a specified period of time. No public or
|
||||
private interaction with the people involved, including unsolicited interaction
|
||||
with those enforcing the Code of Conduct, is allowed during this period.
|
||||
Violating these terms may lead to a permanent ban.
|
||||
|
||||
### 4. Permanent Ban
|
||||
|
||||
**Community Impact**: Demonstrating a pattern of violation of community
|
||||
standards, including sustained inappropriate behavior, harassment of an
|
||||
individual, or aggression toward or disparagement of classes of individuals.
|
||||
|
||||
**Consequence**: A permanent ban from any sort of public interaction within
|
||||
the community.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
||||
version 2.0, available at
|
||||
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
|
||||
|
||||
Community Impact Guidelines were inspired by [Mozilla's code of conduct
|
||||
enforcement ladder](https://github.com/mozilla/diversity).
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
|
||||
For answers to common questions about this code of conduct, see the FAQ at
|
||||
https://www.contributor-covenant.org/faq. Translations are available at
|
||||
https://www.contributor-covenant.org/translations.
|
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"]
|
21
LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022 imsyy
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
245
README.md
@ -1,5 +1,244 @@
|
||||
简体中文 | [English](./README_EN.md)
|
||||
|
||||
<p>
|
||||
<strong><h2>無名の主页 </h2></strong>
|
||||
一个小主页,原来的看够了,重新弄一个
|
||||
<strong><h2>無名の主页</h2></strong>
|
||||
简单的小主页,原来的看够了,重新弄了一个
|
||||
</p>
|
||||
<a title="SSL" target="_blank" href="https://myssl.com/seal/detail?domain=blog.imsyy.top"><img src="https://img.shields.io/badge/MySSL-安全认证-brightgreen"></a> <a title="CDN" target="_blank" href="https://www.upyun.com/?utm_source=lianmeng&utm_medium=referral"><img src="https://img.shields.io/badge/CDN-%E5%8F%88%E6%8B%8D%E4%BA%91-blue"></a> <a title="beian" target="_blank" href="https://beian.miit.gov.cn/"><img src="https://img.shields.io/badge/%E8%B1%ABICP%E5%A4%87-20013231--2%E5%8F%B7-important"></a> <a title="Copyright" target="_blank" href="https://imsyy.top/"><img src="https://img.shields.io/badge/Copyright%20%C2%A9%202020--2021-%E7%84%A1%E5%90%8D-red"></a>
|
||||
|
||||

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

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

|
||||
|
||||
### ⚙️ 手动部署
|
||||
|
||||
- **安装** [node.js](https://nodejs.org/zh-cn/) **环境**
|
||||
|
||||
> node > 16.16.0
|
||||
> npm > 8.15.0
|
||||
|
||||
- 然后以 **管理员权限** 运行 `cmd` 终端,并 `cd` 到 项目根目录
|
||||
- 在 `终端` 中输入:
|
||||
|
||||
```bash
|
||||
# 安装 pnpm
|
||||
npm install -g pnpm
|
||||
|
||||
# 安装依赖
|
||||
pnpm install
|
||||
|
||||
# 预览
|
||||
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` 中可以自定义网站链接(以指向自己的网站):
|
||||
|
||||
```json
|
||||
{
|
||||
"icon": "Blog",
|
||||
"name": "博客",
|
||||
"link": "https://blog.imsyy.top/"
|
||||
},
|
||||
```
|
||||
|
||||
其中 `icon` 网站链接的图标可以在 `src/components/Links/index.vue` 中添加:
|
||||
|
||||
```js
|
||||
// 可前往 https://www.xicons.org 自行挑选并在此处引入
|
||||
// 此处引入的是 fa 类型
|
||||
import {
|
||||
Link,
|
||||
Blog,
|
||||
CompactDisc,
|
||||
Cloud,
|
||||
Compass,
|
||||
Book,
|
||||
Fire,
|
||||
LaptopCode,
|
||||
} from "@vicons/fa";
|
||||
|
||||
...
|
||||
|
||||
// 网站链接图标
|
||||
const siteIcon = {
|
||||
Blog,
|
||||
Cloud,
|
||||
CompactDisc,
|
||||
Compass,
|
||||
Book,
|
||||
Fire,
|
||||
LaptopCode,
|
||||
};
|
||||
```
|
||||
|
||||
### 社交链接
|
||||
|
||||
在 `src/assets/socialLinks.json` 中可以自定义社交链接。
|
||||
|
||||
### 天气
|
||||
|
||||
天气及地区获取需要 `高德开放平台` 相关 API
|
||||
|
||||
- 前往 [高德开放平台控制台](https://console.amap.com/dev/index) 创建一个 `Web 服务` 类型的 `Key`,并将 `Key` 填入 `.env` 中的 `VITE_WEATHER_KEY` 中
|
||||
|
||||
也可自行更换其他方式
|
||||
|
||||
### 音乐
|
||||
|
||||
> 本项目采用了基于 `MetingJS` 的 `Aplayer` 音乐播放器,可实现快速自定义歌单
|
||||
> \*仅支持 **中国大陆地区**
|
||||
|
||||
请在 `.env` 文件中更改歌曲相关参数即可实现自定义歌单列表
|
||||
|
||||
```bash
|
||||
# 歌曲 API 地址
|
||||
VITE_SONG_API = "https://api-meting.imsyy.top"
|
||||
# 歌曲服务器 ( netease-网易云, tencent-qq音乐 )
|
||||
VITE_SONG_SERVER = "netease"
|
||||
# 播放类型 ( song-歌曲, playlist-播放列表, album-专辑, search-搜索, artist-艺术家 )
|
||||
VITE_SONG_TYPE = "playlist"
|
||||
# 播放 ID
|
||||
VITE_SONG_ID = "7452421335"
|
||||
```
|
||||
|
||||
### 字体
|
||||
|
||||
现采用 `HarmonyOS Sans` 开源字体,采用字体拆分,提升加载速度
|
||||
|
||||
> 由于本站 `CDN` 已开启防盗链,**非本站域名不可访问**,请将字体引入链接更改为下方内容,否则 **自定义字体将失效**
|
||||
>
|
||||
> `https://s1.hdslb.com/bfs/static/jinkela/long/font/regular.css`
|
||||
|
||||
<details>
|
||||
<summary>旧版方式</summary>
|
||||
|
||||
> 由于本项目引入了中文字体,需要压缩中文字体以提高网页加载速度( 也可以取消使用中文字体 )
|
||||
|
||||
#### 中文字体去除繁体
|
||||
|
||||
- 安装 `Python 3.7` 和 `pip`
|
||||
- 运行 `pip install fonttools`
|
||||
- 下载 [sc_unicode.txt](https://gist.githubusercontent.com/imaegoo/d64e5088b723c2e02c40985f55ff12db/raw/5ebd2ce49418c73459a9dfe050483409306a6c1d/sc_unicode.txt)
|
||||
- 运行 `pyftsubset 字体名称.ttf --unicodes-file=sc_unicode.txt`
|
||||
|
||||
#### 字体进一步压缩
|
||||
|
||||
- 编译安装 `Google woff2`
|
||||
|
||||
```bash
|
||||
sudo apt-get install -y git g++ make
|
||||
git clone --recursive https://github.com/google/woff2.git
|
||||
cd woff2
|
||||
make clean all
|
||||
```
|
||||
|
||||
- 再压缩字体
|
||||
|
||||
```
|
||||
./woff2_compress ./字体名称.ttf
|
||||
```
|
||||
|
||||
- 最终可对原字体进行缓加载,**先行加载压缩后的字体**
|
||||
|
||||
> 详细信息可前往 [虹墨空间站](https://www.imaegoo.com/2020/chinese-font-compress/) 查看原文
|
||||
|
||||
</details>
|
||||
|
||||
### 网站图标及网站背景
|
||||
|
||||
#### 网站背景
|
||||
|
||||
可以在 `public/images` 中修改网站背景
|
||||
|
||||
如果想要添加更多的本地图片作为网站背景,可以将图片重命名 `background+数字` 的形式,并在 `src/components/Background/index.vue` 中进行修改:
|
||||
|
||||
```js
|
||||
if (type == 0) {
|
||||
// 修改此处 Math.random() 后面的第一个数字为图片的数量
|
||||
bgUrl.value = `/images/background${Math.floor(Math.random() * 10 + 1)}.webp`;
|
||||
}
|
||||
```
|
||||
|
||||
#### 网站图标
|
||||
|
||||
可以在 `public/images/icon` 中修改网站图标。
|
||||
|
||||
### 技术栈
|
||||
|
||||
- [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
|
||||
|
||||
- [韩小韩 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)
|
||||
|
||||
<a title="SSL" target="_blank" href="https://myssl.com/seal/detail?domain=blog.imsyy.top"><img src="https://img.shields.io/badge/MySSL-安全认证-brightgreen"></a> <a title="CDN" target="_blank" href="https://cdnjs.com/"><img src="https://img.shields.io/badge/CDN-Cloudflare-blue"></a> <a title="Copyright" target="_blank" href="https://imsyy.top/"><img src="https://img.shields.io/badge/Copyright%20%C2%A9%202020--2023-%E7%84%A1%E5%90%8D-red"></a>
|
||||
|
144
README_EN.md
Normal file
@ -0,0 +1,144 @@
|
||||
English | [Chinese](./README.md)
|
||||
|
||||
<p>
|
||||
<strong><h2>無名の主页</h2></strong>
|
||||
Simple little homepage, had enough of the original one and made a new one
|
||||
</p>
|
||||
|
||||

|
||||
|
||||
>The logo font on the home page has been compressed, so if you use a font other than this logo, it will change back to the default font, Here is the [full font](https://file.4everland.app/font/Other/Pacifico-Regular.ttf)
|
||||
|
||||
### Demo
|
||||
|
||||
>Due to CDN caching, you may need `Ctrl` + `F5` to force a browser cache refresh to see the latest results
|
||||
|
||||
- [無名の主页](https://www.imsyy.top)
|
||||
- [無名の主页 - Dev](https://home-imsyy.vercel.app)
|
||||
- [無名の主页 - Standby](https://home-5iw.pages.dev)
|
||||
|
||||
### Functions
|
||||
|
||||
- [x] Loading animation
|
||||
- [x] Site description
|
||||
- [x] Hitokoto
|
||||
- [x] Date and time
|
||||
- [x] Live weather
|
||||
- [x] Time progress bar
|
||||
- [x] Music player
|
||||
- [x] Mobile adaptation
|
||||
|
||||
* [ ] Player cancels using Aplayer
|
||||
|
||||
### Deployment
|
||||
|
||||
* **Installation** [node.js](https://nodejs.org/zh-cn/) **Environment**
|
||||
|
||||
> node > 16.16.0
|
||||
> npm > 8.15.0
|
||||
|
||||
* Then run the `cmd` terminal with **administrator privileges** and `cd` to the project root directory
|
||||
* In the `terminal` type:
|
||||
|
||||
```bash
|
||||
# Install pnpm
|
||||
npm install -g pnpm
|
||||
|
||||
# Install the dependencies
|
||||
pnpm install
|
||||
|
||||
# Preview
|
||||
pnpm dev
|
||||
|
||||
# Build
|
||||
pnpm build
|
||||
```
|
||||
|
||||
> Once the build is complete, the files in the `dist` folder can be uploaded to the server or imported and automatically deployed with one click using a hosting platform such as `Vercel`.
|
||||
|
||||
### Weather
|
||||
|
||||
Weather and area access requires `高德开放平台` related API
|
||||
|
||||
- Go to [高德开放平台控制台](https://console.amap.com/dev/index) to create a `Key` of type `Web Service` and fill the `Key` into `VITE_WEATHER_KEY` in `.env`
|
||||
|
||||
It can also be replaced by other methods
|
||||
|
||||
### Music
|
||||
|
||||
>This project uses the `Aplayer` music player based on `MetingJS` for quick song list customization
|
||||
>*Only supported in **Mainland China**
|
||||
|
||||
Please change the song related parameters in the `.env` file to customize the song list
|
||||
|
||||
```bash
|
||||
# Songs API address
|
||||
VITE_SONG_API = "https://api-meting.imsyy.top"
|
||||
# Song server ( netease-netease, tencent-qq music )
|
||||
VITE_SONG_SERVER = "netease"
|
||||
# Playback type ( song-song, playlist-playlist, album-album, search-search, artist-artist )
|
||||
VITE_SONG_TYPE = "playlist"
|
||||
# Playback ID
|
||||
VITE_SONG_ID = "7452421335"
|
||||
```
|
||||
|
||||
### Fonts
|
||||
|
||||
Now using `HarmonyOS Sans` open source font, using font splitting to improve loading speed
|
||||
|
||||
>Because this site's `CDN` has opened anti-leech, **non-site domain name is not accessible**, please change the font import link to the following content, otherwise **custom fonts will be invalid**
|
||||
>
|
||||
>`https://cdn.jsdelivr.net/gh/imsyy/file/font/HarmonyOS_Sans/regular.min.css`
|
||||
|
||||
<details>
|
||||
<summary>old way</summary>
|
||||
|
||||
>As Chinese fonts are introduced in this project, Chinese fonts need to be compressed to improve the loading speed of the page (you can also cancel the use of Chinese fonts)
|
||||
|
||||
#### Chinese font removal traditional
|
||||
|
||||
- Install `Python 3.7` and `pip`
|
||||
- Run `pip install fonttools`
|
||||
- Download [sc_unicode.txt](https://gist.githubusercontent.com/imaegoo/d64e5088b723c2e02c40985f55ff12db/raw/5ebd2ce49418c73459a9dfe050483409306a6c1d/sc_unicode.txt)
|
||||
- Run `pyftsubset font-name.ttf --unicodes-file=sc_unicode.txt`
|
||||
|
||||
#### fonts further compressed
|
||||
|
||||
- Compile and install ``Google woff2``
|
||||
|
||||
```bash
|
||||
sudo apt-get install -y git g++ make
|
||||
git clone --recursive https://github.com/google/woff2.git
|
||||
cd woff2
|
||||
make clean all
|
||||
```
|
||||
|
||||
- Compress the font again
|
||||
|
||||
```
|
||||
. /woff2_compress . /font_name.ttf
|
||||
```
|
||||
|
||||
- Eventually the original font can be slow loaded, **load the compressed font first**
|
||||
|
||||
>For more information, please go to [虹墨空间站](https://www.imaegoo.com/2020/chinese-font-compress/) to view the original article
|
||||
|
||||
</details>
|
||||
|
||||
### Technology Stack
|
||||
|
||||
* [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
|
||||
|
||||
* [韩小韩 WebAPI 接口](https://api.vvhan.com/)
|
||||
* [搏天 API](https://api.btstu.cn/doc/sjbz.php)
|
||||
* [高德开放平台](https://lbs.amap.com/)
|
||||
* [Hitokoto 一言](https://hitokoto.cn/)
|
||||
|
||||
<a title="SSL" target="_blank" href="https://myssl.com/seal/detail?domain=blog.imsyy.top"><img src="https://img.shields.io/badge/MySSL-安全认证-brightgreen"></a> <a title="CDN" target="_blank" href="https://cdnjs.com/"><img src="https://img.shields.io/badge/CDN-Cloudflare-blue"></a> <a title="Copyright" target="_blank" href="https://imsyy.top/"><img src="https://img.shields.io/badge/Copyright%20%C2%A9%202020--2023-%E7%84%A1%E5%90%8D-red"></a>
|
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
@ -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']
|
||||
}
|
||||
}
|
@ -1,89 +0,0 @@
|
||||
/*模糊渐入动画*/
|
||||
@keyframes fade-in {
|
||||
0% {
|
||||
opacity: 0;
|
||||
backdrop-filter: blur(0px);
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 1;
|
||||
backdrop-filter: blur(10px);
|
||||
}
|
||||
}
|
||||
|
||||
@-webkit-keyframes fade-in {
|
||||
0% {
|
||||
opacity: 0;
|
||||
backdrop-filter: blur(0px);
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 1;
|
||||
backdrop-filter: blur(10px);
|
||||
}
|
||||
}
|
||||
|
||||
@-moz-keyframes fade-in {
|
||||
0% {
|
||||
opacity: 0;
|
||||
backdrop-filter: blur(0px);
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 1;
|
||||
backdrop-filter: blur(10px);
|
||||
}
|
||||
}
|
||||
|
||||
@-o-keyframes fade-in {
|
||||
0% {
|
||||
opacity: 0;
|
||||
backdrop-filter: blur(0px);
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 1;
|
||||
backdrop-filter: blur(10px);
|
||||
}
|
||||
}
|
||||
|
||||
/*渐入动画*/
|
||||
@keyframes fade {
|
||||
0% {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@-webkit-keyframes fade {
|
||||
0% {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@-moz-keyframes fade {
|
||||
0% {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@-o-keyframes fade {
|
||||
0% {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
64
css/font.css
@ -1,64 +0,0 @@
|
||||
@font-face {
|
||||
font-family: "iconfont";
|
||||
src: url('../font/font_2831425_80aedhvquju.woff2') format('woff2'),
|
||||
url('../font/font_2831425_80aedhvquju.woff') format('woff'),
|
||||
url('../font/font_2831425_80aedhvquju.ttf') format('truetype');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Pacifico-Regular";
|
||||
src: url('../font/Pacifico-Regular.ttf');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "UnidreamLED";
|
||||
src: url('../font/UnidreamLED.ttf');
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
font-family: "iconfont" !important;
|
||||
font-size: 16px;
|
||||
font-style: normal;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.icon-youxiang:before {
|
||||
content: "\e605";
|
||||
}
|
||||
|
||||
.icon-github:before {
|
||||
content: "\e691";
|
||||
}
|
||||
|
||||
.icon-telegram1:before {
|
||||
content: "\e731";
|
||||
}
|
||||
|
||||
.icon-QQ:before {
|
||||
content: "\e882";
|
||||
}
|
||||
|
||||
.icon-twitter:before {
|
||||
content: "\e883";
|
||||
}
|
||||
|
||||
.icon-github1:before {
|
||||
content: "\e799";
|
||||
}
|
||||
|
||||
.icon-weixin:before {
|
||||
content: "\e600";
|
||||
}
|
||||
|
||||
.icon-telegram:before {
|
||||
content: "\e8db";
|
||||
}
|
||||
|
||||
.icon-yinhao-copy:before {
|
||||
content: "\e608";
|
||||
}
|
||||
|
||||
.icon-yinhao-copy-copy:before {
|
||||
content: "\e62e";
|
||||
}
|
125
css/loading.css
@ -1,125 +0,0 @@
|
||||
#loading-box .loading-left-bg,
|
||||
#loading-box .loading-right-bg {
|
||||
position: fixed;
|
||||
z-index: 999998;
|
||||
width: 50%;
|
||||
height: 100%;
|
||||
background-color: rgb(81 81 81 / 80%);
|
||||
transition: all 0.7s cubic-bezier(0.42, 0, 0, 1.01);
|
||||
backdrop-filter: blur(40px);
|
||||
}
|
||||
|
||||
#loading-box .loading-right-bg {
|
||||
right: 0;
|
||||
}
|
||||
|
||||
#loading-box>.spinner-box {
|
||||
position: fixed;
|
||||
z-index: 999999;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
#loading-box .spinner-box .loading-word {
|
||||
position: absolute;
|
||||
color: #ffffff;
|
||||
font-size: 0.95rem;
|
||||
transform: translateY(64px);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
p.loading-title {
|
||||
font-size: 1.25rem;
|
||||
margin: 20px 10px 4px 10px;
|
||||
}
|
||||
|
||||
#loading-box .spinner-box .configure-core {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: #37474f;
|
||||
}
|
||||
|
||||
div.loaded div.loading-left-bg {
|
||||
transform: translate(-100%, 0);
|
||||
}
|
||||
|
||||
div.loaded div.loading-right-bg {
|
||||
transform: translate(100%, 0);
|
||||
}
|
||||
|
||||
div.loaded div.spinner-box {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.loader {
|
||||
position: absolute;
|
||||
top: calc(50% - 32px);
|
||||
left: calc(50% - 32px);
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
border-radius: 50%;
|
||||
perspective: 800px;
|
||||
transition: all 0.7s cubic-bezier(0.42, 0, 0, 1.01);
|
||||
}
|
||||
|
||||
.inner {
|
||||
position: absolute;
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.inner.one {
|
||||
left: 0%;
|
||||
top: 0%;
|
||||
animation: rotate-one 1s linear infinite;
|
||||
border-bottom: 3px solid #EFEFFA;
|
||||
}
|
||||
|
||||
.inner.two {
|
||||
right: 0%;
|
||||
top: 0%;
|
||||
animation: rotate-two 1s linear infinite;
|
||||
border-right: 3px solid #EFEFFA;
|
||||
}
|
||||
|
||||
.inner.three {
|
||||
right: 0%;
|
||||
bottom: 0%;
|
||||
animation: rotate-three 1s linear infinite;
|
||||
border-top: 3px solid #EFEFFA;
|
||||
}
|
||||
|
||||
@keyframes rotate-one {
|
||||
0% {
|
||||
transform: rotateX(35deg) rotateY(-45deg) rotateZ(0deg);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: rotateX(35deg) rotateY(-45deg) rotateZ(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes rotate-two {
|
||||
0% {
|
||||
transform: rotateX(50deg) rotateY(10deg) rotateZ(0deg);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: rotateX(50deg) rotateY(10deg) rotateZ(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes rotate-three {
|
||||
0% {
|
||||
transform: rotateX(35deg) rotateY(55deg) rotateZ(0deg);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: rotateX(35deg) rotateY(55deg) rotateZ(360deg);
|
||||
}
|
||||
}
|
225
css/mobile.css
@ -1,225 +0,0 @@
|
||||
@charset"utf-8";
|
||||
|
||||
/*小于1400px时*/
|
||||
@media (max-width: 1400px) {
|
||||
|
||||
/*时钟显示*/
|
||||
span#win_text,
|
||||
span#win_speed {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
/*小于1200px时*/
|
||||
@media (max-width: 1200px) {
|
||||
|
||||
/*总布局*/
|
||||
.container,
|
||||
.container-lg,
|
||||
.container-md,
|
||||
.container-sm {
|
||||
max-width: 1100px !important;
|
||||
}
|
||||
|
||||
/*天气模块*/
|
||||
.weather {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.weekday {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
/*小于992px时*/
|
||||
@media (max-width: 992px) {
|
||||
|
||||
/*一言*/
|
||||
.col.hitokotos {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/*日期显示*/
|
||||
.weekday {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
/*标题文字*/
|
||||
.main-img img {
|
||||
width: 110px;
|
||||
}
|
||||
|
||||
span.img-title {
|
||||
font-size: 4.75rem;
|
||||
}
|
||||
|
||||
span.img-text {
|
||||
font-size: 1.75rem;
|
||||
}
|
||||
}
|
||||
|
||||
/*小于789px时*/
|
||||
@media (max-width: 789px) {
|
||||
|
||||
/*标题文字*/
|
||||
span.img-text {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
/*小于768px时*/
|
||||
@media (max-width: 768px) {
|
||||
|
||||
/*标题文字*/
|
||||
.main-img img {
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
span.img-title {
|
||||
font-size: 4.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
/*小于660px时*/
|
||||
@media (max-width: 660px) {
|
||||
|
||||
/*左侧栏高度*/
|
||||
.main-left {
|
||||
transform: translateY(20px);
|
||||
}
|
||||
|
||||
/*右侧栏隐藏*/
|
||||
.col.right {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/*标题文字*/
|
||||
span.img-text {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
/*简介*/
|
||||
.message {
|
||||
max-width: 100%;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/*
|
||||
.des {
|
||||
justify-content: space-between;
|
||||
}
|
||||
*/
|
||||
|
||||
/*社交链接*/
|
||||
.social {
|
||||
max-width: 100%;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
#link-text {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.link i {
|
||||
margin: 0px 20px;
|
||||
}
|
||||
|
||||
/*菜单栏按钮*/
|
||||
.menu {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
position: fixed;
|
||||
top: 84%;
|
||||
}
|
||||
|
||||
.munu-button {
|
||||
padding: 5px 20px;
|
||||
background: rgb(0 0 0 / 20%);
|
||||
backdrop-filter: blur(10px);
|
||||
border-radius: 6px;
|
||||
font-size: 1.25rem;
|
||||
transition: 0.5s;
|
||||
}
|
||||
|
||||
/*页脚文字*/
|
||||
footer {
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@media (min-width: 660px) {
|
||||
.menu {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
/*小于390px时*/
|
||||
@media (max-width: 390px) {
|
||||
.main-img img {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
菜单按钮
|
||||
*/
|
||||
.menus .col.left {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.menus .col.right {
|
||||
display: block !important;
|
||||
transition: 0.5s;
|
||||
padding: 0rem 0.75rem;
|
||||
}
|
||||
|
||||
/*功能区调整*/
|
||||
.menus .col.hitokotos {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.menus .col.times {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/*边界布局*/
|
||||
.menus .row {
|
||||
--bs-gutter-x: 0rem;
|
||||
}
|
||||
|
||||
.menus .col.\32 {
|
||||
margin: 0 0.75rem;
|
||||
}
|
||||
|
||||
.menus .logo {
|
||||
display: inline !important;
|
||||
position: fixed;
|
||||
top: 8%;
|
||||
font-family: 'Pacifico-Regular';
|
||||
font-size: 1.75rem;
|
||||
}
|
||||
|
||||
/*切换动画*/
|
||||
.hitokoto,
|
||||
.time,
|
||||
.link-card,
|
||||
.message {
|
||||
animation: fade-in;
|
||||
-webkit-animation: fade-in 0.5s;
|
||||
-moz-animation: fade-in 0.5s;
|
||||
-o-animation: fade-in 0.5s;
|
||||
-ms-animation: fade-in 0.5s;
|
||||
}
|
||||
|
||||
.logo,
|
||||
.line,
|
||||
.main-img,
|
||||
.social {
|
||||
animation: fade 0.5;
|
||||
-webkit-animation: fade 0.5s;
|
||||
-moz-animation: fade 0.5s;
|
||||
-o-animation: fade 0.5s;
|
||||
-ms-animation: fade 0.5s;
|
||||
}
|
323
css/style.css
@ -1,323 +0,0 @@
|
||||
@charset"utf-8";
|
||||
/*全局样式*/
|
||||
html,
|
||||
body {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
*,
|
||||
a,
|
||||
p {
|
||||
text-decoration: none;
|
||||
transition: 0.3s;
|
||||
color: #efefef;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.cards {
|
||||
transition: 0.5s;
|
||||
}
|
||||
|
||||
.cards:hover {
|
||||
transform: scale(1.01);
|
||||
transition: 0.5s;
|
||||
}
|
||||
|
||||
.cards:active {
|
||||
transform: scale(0.95);
|
||||
transition: 0.5s;
|
||||
}
|
||||
|
||||
/*页面样式*/
|
||||
section {
|
||||
display: block;
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
main {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgb(0 0 0 / 20%);
|
||||
display: flex;
|
||||
/*align-items: center;*/
|
||||
}
|
||||
|
||||
.container {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
}
|
||||
|
||||
.row {
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.main-left {
|
||||
/*transform: translateY(240px);*/
|
||||
transform: translateY(40px);
|
||||
}
|
||||
/*
|
||||
.main-right {
|
||||
transform: translateY(38%);
|
||||
}
|
||||
*/
|
||||
.row.rightone {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
/*头像*/
|
||||
.main-img {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.main-img img {
|
||||
border-radius: 50%;
|
||||
width: 120px;
|
||||
}
|
||||
|
||||
.img-title {
|
||||
width: 100%;
|
||||
margin-left: 12px;
|
||||
font-family: Pacifico-Regular;
|
||||
transform: translateY(-8%);
|
||||
}
|
||||
|
||||
span.img-title {
|
||||
font-size: 5rem;
|
||||
}
|
||||
|
||||
span.img-text {
|
||||
font-size: 2rem;
|
||||
}
|
||||
|
||||
/*简介*/
|
||||
.message {
|
||||
background: rgb(0 0 0 / 25%);
|
||||
backdrop-filter: blur(10px);
|
||||
/*margin: 0.5rem;*/
|
||||
padding: 1rem;
|
||||
border-radius: 6px;
|
||||
margin-top: 3.5rem;
|
||||
max-width: 460px;
|
||||
}
|
||||
|
||||
.des {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
p.des-title {
|
||||
margin: 1rem 1rem;
|
||||
line-height: 2rem;
|
||||
font-family: Pacifico-Regular;
|
||||
}
|
||||
|
||||
i.iconfont.icon-yinhao-copy {
|
||||
align-self: flex-end;
|
||||
}
|
||||
|
||||
/*社交链接*/
|
||||
.social {
|
||||
margin-top: 1rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
max-width: 460px;
|
||||
}
|
||||
|
||||
.link i {
|
||||
font-size: 1.75rem;
|
||||
margin: 0px 10px;
|
||||
}
|
||||
|
||||
#link-text {
|
||||
display: none;
|
||||
flex: 1;
|
||||
text-align: right;
|
||||
margin-right: 1rem;
|
||||
}
|
||||
|
||||
/*一言*/
|
||||
.hitokoto {
|
||||
width: 100%;
|
||||
background: rgb(0 0 0 / 25%);
|
||||
backdrop-filter: blur(10px);
|
||||
padding: 20px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.hitokoto-all {
|
||||
margin-top: 10px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.hitokoto-from {
|
||||
margin-top: 10px;
|
||||
font-weight: bold;
|
||||
align-self: flex-end;
|
||||
}
|
||||
|
||||
/*时间卡片*/
|
||||
.time {
|
||||
width: 100%;
|
||||
background: rgb(0 0 0 / 25%);
|
||||
backdrop-filter: blur(10px);
|
||||
padding: 20px;
|
||||
border-radius: 6px;
|
||||
text-align: center;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
span.time-text {
|
||||
font-size: 3.25rem;
|
||||
letter-spacing: 2px;
|
||||
font-family: UnidreamLED;
|
||||
}
|
||||
|
||||
/*链接卡片*/
|
||||
.line {
|
||||
margin: 1rem 0.25rem;
|
||||
margin-top: 2rem;
|
||||
font-size: 1.10rem;
|
||||
}
|
||||
|
||||
.link-card {
|
||||
height: 100px;
|
||||
width: 100%;
|
||||
border-radius: 6px;
|
||||
background: rgb(0 0 0 / 25%);
|
||||
backdrop-filter: blur(10px);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
justify-content: space-evenly;
|
||||
}
|
||||
|
||||
.link-card:hover {
|
||||
background: rgb(0 0 0 / 40%);
|
||||
transition: 0.5s;
|
||||
}
|
||||
|
||||
/*更多页面*/
|
||||
.more {
|
||||
display: none;
|
||||
width: 46%;
|
||||
z-index: 999;
|
||||
position: fixed;
|
||||
height: 82%;
|
||||
right: 4%;
|
||||
background: rgb(0 0 0 / 25%);
|
||||
backdrop-filter: blur(10px);
|
||||
top: 7%;
|
||||
border-radius: 6px;
|
||||
padding: 30px;
|
||||
}
|
||||
|
||||
.mores .more {
|
||||
display: flex;
|
||||
justify-content: space-evenly;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
animation: fade;
|
||||
-webkit-animation: fade 0.3s;
|
||||
-moz-animation: fade 0.3s;
|
||||
-o-animation: fade 0.3s;
|
||||
-ms-animation: fade 0.3s;
|
||||
}
|
||||
|
||||
.mores .col.right {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.close {
|
||||
left: auto;
|
||||
top: 4px;
|
||||
right: 8px;
|
||||
font-size: 1.45rem;
|
||||
}
|
||||
|
||||
/*进度条*/
|
||||
.progress {
|
||||
width: 100%;
|
||||
height: 20px;
|
||||
align-items: center;
|
||||
background: rgb(255 255 255 / 25%) !important;
|
||||
backdrop-filter: blur(5px);
|
||||
}
|
||||
|
||||
.progress-bar {
|
||||
font-family: 'UnidreamLED';
|
||||
background-color: #efefef !important;
|
||||
color: rgb(86 77 89) !important;
|
||||
font-size: 0.95rem;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
/*时间胶囊*/
|
||||
|
||||
.date {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.date-text {
|
||||
margin: 1rem 0rem 0.5rem 0rem;
|
||||
}
|
||||
|
||||
/*更多页面链接*/
|
||||
|
||||
.mores .link-card {
|
||||
height: 48px !important;
|
||||
}
|
||||
|
||||
/*页脚样式*/
|
||||
footer {
|
||||
text-align: center;
|
||||
height: 46px;
|
||||
backdrop-filter: blur(10px);
|
||||
background: rgb(0 0 0 / 25%);
|
||||
}
|
||||
|
||||
.power {
|
||||
line-height: 46px;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
/*弹窗样式*/
|
||||
.iziToast {
|
||||
background: rgb(0 0 0 / 45%) !important;
|
||||
backdrop-filter: blur(10px) !important;
|
||||
}
|
||||
|
||||
.iziToast-body .iziToast-message {
|
||||
line-height: 18px !important;
|
||||
}
|
||||
|
||||
.iziToast:after {
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
.iziToast-message.slideIn {
|
||||
margin-top: 5px !important;
|
||||
}
|
||||
|
||||
.iziToast-message {
|
||||
word-break: break-all !important;
|
||||
}
|
||||
|
||||
.iziToast>.iziToast-close {
|
||||
background: url(https://cdn.jsdelivr.net/gh/imsyy/file/pic/close.png) no-repeat 50% 50% !important;
|
||||
background-size: 8px !important;
|
||||
}
|
9
docker-compose.yml
Normal file
@ -0,0 +1,9 @@
|
||||
version: '3'
|
||||
|
||||
services:
|
||||
app:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
ports:
|
||||
- "12445:12445"
|
BIN
favicon.ico
Before Width: | Height: | Size: 4.2 KiB |
Before Width: | Height: | Size: 14 KiB |
BIN
img/weixin.png
Before Width: | Height: | Size: 39 KiB |
333
index.html
@ -1,304 +1,39 @@
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="zh-CN">
|
||||
|
||||
<head>
|
||||
<!-- 基础信息 -->
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="Access-Control-Allow-Origin" content="*">
|
||||
<meta name="renderer" content="webkit" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
|
||||
<meta name="force-rendering" content="webkit" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="description" content="無名の主页">
|
||||
<meta name="keywords" content="無名,个人主页">
|
||||
<meta name="author" content="無名">
|
||||
<title>無名の主页</title>
|
||||
<!-- 引入样式 -->
|
||||
<link rel="stylesheet" type="text/css"
|
||||
href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.1/dist/css/bootstrap.min.css">
|
||||
<link rel="stylesheet" type="text/css" href="./css/style.css">
|
||||
<link rel="stylesheet" type="text/css" href="./css/mobile.css">
|
||||
<link rel="stylesheet" type="text/css" href="./css/font.css">
|
||||
<link rel="stylesheet" type="text/css" href="./css/loading.css">
|
||||
<link rel="stylesheet" type="text/css" href="./css/animation.css">
|
||||
<link rel="icon" href="./favicon.ico">
|
||||
<link rel="apple-touch-icon" href="./img/apple-touch-icon.png">
|
||||
<!-- 引入 Izitoast -->
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/izitoast@1.4.0/dist/css/iziToast.min.css">
|
||||
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/izitoast@1.4.0/dist/js/iziToast.min.js"></script>
|
||||
<!-- 引入 Fontawesome -->
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/volantis-x/cdn-fontawesome-pro@master/css/all.min.css"
|
||||
media="all">
|
||||
<!--引入 Vue-->
|
||||
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.min.js"></script>
|
||||
<!-- 引入 jQuery -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.min.js"></script>
|
||||
<!-- 百度统计 -->
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<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="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%" />
|
||||
<meta name="description" content="%VITE_SITE_DES%" />
|
||||
<meta name="keywords" content="%VITE_SITE_KEYWORDS%" />
|
||||
<meta name="author" content="%VITE_SITE_ANTHOR%" />
|
||||
<meta name="theme-color" content="#424242" />
|
||||
<title>%VITE_SITE_NAME%</title>
|
||||
<!-- HarmonyOS Sans -->
|
||||
<!-- 本站 CDN 已开启防盗链,非本站域名不可访问,请更改链接为下方内容,否则自定义字体将失效 -->
|
||||
<link rel="stylesheet" href="https://s1.hdslb.com/bfs/static/jinkela/long/font/regular.css" />
|
||||
<!-- <link rel="stylesheet" href="https://cdn.imsyy.top/gh/imsyy/file/font/HarmonyOS_Sans/regular.min.css" /> -->
|
||||
<!-- IE Out -->
|
||||
<script>
|
||||
var _hmt = _hmt || [];
|
||||
(function () {
|
||||
var hm = document.createElement("script");
|
||||
hm.src = "https://hm.baidu.com/hm.js?14e9f35ff8bc67fd4bcb5f07a6e6655a";
|
||||
var s = document.getElementsByTagName("script")[0];
|
||||
s.parentNode.insertBefore(hm, s);
|
||||
})();
|
||||
if (/*@cc_on!@*/ false || (!!window.MSInputMethodContext && !!document.documentMode))
|
||||
window.location.href =
|
||||
'https://support.dmeng.net/upgrade-your-browser.html?referrer=' +
|
||||
encodeURIComponent(window.location.href);
|
||||
</script>
|
||||
<!-- IE 淘汰计划 -->
|
||||
<script>
|
||||
if ( /*@cc_on!@*/ false || (!!window.MSInputMethodContext && !!document.documentMode)) window.location.href =
|
||||
"/upgrade-your-browser/index.html?referrer=" + encodeURIComponent(window.location.href);
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<!--加载动画-->
|
||||
<div id="loading-box">
|
||||
<div class="loading-left-bg"></div>
|
||||
<div class="loading-right-bg"></div>
|
||||
<div class="spinner-box">
|
||||
<div class="loader">
|
||||
<div class="inner one"></div>
|
||||
<div class="inner two"></div>
|
||||
<div class="inner three"></div>
|
||||
</div>
|
||||
<div class="loading-word">
|
||||
<p class="loading-title">無名の主页</p>加载中
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!--加载动画结束-->
|
||||
<section id="section" class="section">
|
||||
<main id="main" class="main">
|
||||
<div class="container" id="container">
|
||||
<div class="row">
|
||||
<div class="col left">
|
||||
<!--基本信息-->
|
||||
<div class="main-left">
|
||||
<!--Logo-->
|
||||
<div class="main-img">
|
||||
<img src="./img/logo.png" alt="img">
|
||||
<div class="img-title">
|
||||
<span class="img-title">imsyy</span>
|
||||
<span class="img-text">.top</span>
|
||||
</div>
|
||||
</div>
|
||||
<!--介绍信息-->
|
||||
<div class="message cards" onclick="switchMore()">
|
||||
<div class="des" id="des"><i class="iconfont icon-yinhao-copy-copy"></i>
|
||||
<p class="des-title"><span id="change">Hello World !</span><br /><span
|
||||
id="change1">一个建立于 21 世纪的小站,存活于互联网的边缘</span></p>
|
||||
<i class="iconfont icon-yinhao-copy"></i>
|
||||
</div>
|
||||
</div>
|
||||
<!--社交链接-->
|
||||
<div class="social" id="social">
|
||||
<a href="https://github.com/imsyy" class="link" id="github" target="_blank">
|
||||
<i class="iconfont icon-github"></i>
|
||||
</a>
|
||||
<a href="http://wpa.qq.com/msgrd?v=3&uin=1539250352&site=qq&menu=yes" class="link"
|
||||
id="qq" target="_blank">
|
||||
<i class="iconfont icon-QQ"></i>
|
||||
</a>
|
||||
<a href="mailto:one@imsyy.top" class="link" id="email">
|
||||
<i class="iconfont icon-youxiang"></i>
|
||||
</a>
|
||||
<a href="https://t.me/bottom_user" class="link" id="telegram" target="_blank">
|
||||
<i class="iconfont icon-telegram"></i>
|
||||
</a>
|
||||
<a href="https://twitter.com/iimmsyy" class="link" id="twitter" target="_blank">
|
||||
<i class="iconfont icon-twitter"></i>
|
||||
</a>
|
||||
<a id="link-text">通过这里联系我</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col right">
|
||||
<div class="main-right">
|
||||
<!--功能区-->
|
||||
<div class="row rightone">
|
||||
<div class="col hitokotos">
|
||||
<!--一言-->
|
||||
<div class="hitokoto cards" id="hitokoto">
|
||||
<div class="hitokoto-ico"><i class="fad fa-comment-alt-lines"></i> 一言</div>
|
||||
<div class="hitokoto-all">
|
||||
<div class="hitokoto-text"><span id="hitokoto_text">每一个人都应该明确自己的方向和位置</span>
|
||||
</div>
|
||||
<div class="hitokoto-from">-「 <span id="from_text">無名</span> 」
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col times">
|
||||
<!--时间-->
|
||||
<div class="time cards">
|
||||
<div class="timeshow" id="time"></div>
|
||||
<div class="weather">
|
||||
<span id="city_text">天气</span> <span
|
||||
id="wea_text">加载失败</span> <span id="tem_night">*</span>°C~<span
|
||||
id="tem_day">*</span>°C <span id="win_text">风向</span><span
|
||||
id="win_speed">*</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!--分隔线-->
|
||||
<div class="line">
|
||||
<i class="fad fa-grip-lines-vertical"></i>
|
||||
<span class="line-text">网站列表</span>
|
||||
</div>
|
||||
<!--网站链接-->
|
||||
<div class="link">
|
||||
<!--第一组-->
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<a href="https://blog.imsyy.top/" target="_blank">
|
||||
<div class="link-card cards">
|
||||
<i class="fad fa-blog"></i>
|
||||
<span class="link-name">博客</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col 2">
|
||||
<a href="https://web.imsyy.top/" target="_blank">
|
||||
<div class="link-card cards">
|
||||
<i class="fad fa-spider-web"></i>
|
||||
<span class="link-name">网址导航</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col">
|
||||
<a href="https://music.imsyy.top/" target="_blank">
|
||||
<div class="link-card cards">
|
||||
<i class="fad fa-list-music"></i>
|
||||
<span class="link-name">音乐</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<!--第二组-->
|
||||
<div class="row" style="margin-top: 1.5rem;">
|
||||
<div class="col">
|
||||
<a href="https://lab.imsyy.top/" target="_blank">
|
||||
<div class="link-card cards">
|
||||
<i class="fad fa-flask"></i>
|
||||
<span class="link-name">实验室</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col 2">
|
||||
<a href="https://share.imsyy.top/" target="_blank">
|
||||
<div class="link-card cards">
|
||||
<i class="fad fa-cloud-download"></i>
|
||||
<span class="link-name">网盘</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col">
|
||||
<a href="https://blog.imsyy.top/about/" target="_blank">
|
||||
<div class="link-card cards">
|
||||
<i class="fad fa-info-circle"></i>
|
||||
<span class="link-name">关于</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!--展开菜单按钮-->
|
||||
<div class="menu">
|
||||
<a class="munu-button cards" id="menu" onclick="switchMenu()"><i class="fad fa-bars"></i></a>
|
||||
</div>
|
||||
<!--第二屏 Logo-->
|
||||
<div class="logo" style="display: none;">
|
||||
<a>imsyy.top</a>
|
||||
</div>
|
||||
<!--更多内容-->
|
||||
<div class="more cards">
|
||||
<div class="close fixed-top" onclick="switchMore()"><i class="fad fa-times-circle"></i></div>
|
||||
<div class="line" style="margin-top: 1rem;">
|
||||
<i class="fad fa-grip-lines-vertical"></i>
|
||||
<span class="line-text">时间胶囊</span>
|
||||
<i class="fad fa-grip-lines-vertical"></i>
|
||||
</div>
|
||||
<div class="date" id="date">
|
||||
<p class="date-text" style="margin-top: 0rem;">今日已经度过了大约 {{hour}} 小时</p>
|
||||
<div v-html="jinduT()" class="marginbottom"></div>
|
||||
<p class="date-text">本周已经度过了 {{week}} 天,今天是第 {{curweek}} 天</p>
|
||||
<div v-html="jinduZ()" class="marginbottom"></div>
|
||||
<p class="date-text">本月已经度过了 {{day}} 天,今天是第 {{curday}} 天</p>
|
||||
<div v-html="jinduD()" class="marginbottom"></div>
|
||||
<p class="date-text">{{year}} 年已经度过了 {{month}} 个月,度过了 {{outday}} 天</p>
|
||||
<div v-html="jinduY()" class="marginbottom"></div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<i class="fad fa-grip-lines-vertical"></i>
|
||||
<span class="line-text">杂七杂八</span>
|
||||
<i class="fad fa-grip-lines-vertical"></i>
|
||||
</div>
|
||||
<!--网站链接-->
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<a href="https://status.imsyy.top/" target="_blank">
|
||||
<div class="link-card cards">
|
||||
<span class="link-name">站点监测</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col 2">
|
||||
<a href="https://player.imsyy.top/" target="_blank">
|
||||
<div class="link-card cards">
|
||||
<span class="link-name">播放器</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col">
|
||||
<a href="https://write.imsyy.top/" target="_blank">
|
||||
<div class="link-card cards">
|
||||
<span class="link-name">Markdown</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" style="margin-top: 1.5rem;">
|
||||
<div class="col">
|
||||
<a href="https://img.imsyy.top/" target="_blank">
|
||||
<div class="link-card cards">
|
||||
<span class="link-name">图片站</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col 2">
|
||||
<a href="https://file.imsyy.top/" target="_blank">
|
||||
<div class="link-card cards">
|
||||
<span class="link-name">文件站</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col">
|
||||
<a>
|
||||
<div class="link-card cards">
|
||||
<span class="link-name">还没搞</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
<footer id="footer" class="fixed-bottom footer">
|
||||
<div class="power">Copyright © 2020
|
||||
<script>
|
||||
document.write(' - ' + (new Date()).getFullYear())
|
||||
</script> 無名 | <a href="https://beian.miit.gov.cn/" target="_blank">豫ICP备20013231-2号</a>
|
||||
</div>
|
||||
</footer>
|
||||
</section>
|
||||
<!-- JS -->
|
||||
<script type="text/javascript" src="./js/main.js"></script>
|
||||
<script type="text/javascript" src="./js/time.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.1/dist/js/bootstrap.bundle.min.js"></script>
|
||||
</body>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<!-- 主体内容 -->
|
||||
<div id="app"></div>
|
||||
<!-- noscript -->
|
||||
<noscript>
|
||||
<div style="text-align: center">请开启 JavaScript</div>
|
||||
</noscript>
|
||||
<script type="module" src="/src/main.js"></script>
|
||||
</body>
|
||||
</html>
|
215
js/main.js
@ -1,215 +0,0 @@
|
||||
//弹窗样式
|
||||
iziToast.settings({
|
||||
timeout: 10000,
|
||||
icon: 'Fontawesome',
|
||||
closeOnEscape: 'true',
|
||||
position: 'topLeft',
|
||||
transitionIn: 'bounceInRight',
|
||||
transitionOut: 'fadeOutLeft',
|
||||
displayMode: '2',
|
||||
layout: '2',
|
||||
titleColor: '#efefef',
|
||||
messageColor: '#efefef',
|
||||
iconColor: '#efefef',
|
||||
});
|
||||
|
||||
iziToast.info({
|
||||
icon: 'fad fa-vial',
|
||||
title: '新版站点试运行',
|
||||
message: '还存在亿些小问题 ~ <a href="./old/" style="color:#efefef">返回旧版</a>'
|
||||
});
|
||||
|
||||
//获取一言
|
||||
fetch('https://v1.hitokoto.cn')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
const hitokoto = document.getElementById('hitokoto_text')
|
||||
const from = document.getElementById('from_text')
|
||||
hitokoto.innerText = data.hitokoto
|
||||
from.innerText = data.from
|
||||
})
|
||||
.catch(console.error)
|
||||
|
||||
//获取天气
|
||||
fetch('https://www.tianqiapi.com/free/day?appid=43986679&appsecret=TksqGZT7')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
const wea = document.getElementById('wea_text')
|
||||
const city = document.getElementById('city_text')
|
||||
const tem_night = document.getElementById('tem_night')
|
||||
const tem_day = document.getElementById('tem_day')
|
||||
const win = document.getElementById('win_text')
|
||||
const win_speed = document.getElementById('win_speed')
|
||||
wea.innerText = data.wea
|
||||
city.innerText = data.city
|
||||
tem_night.innerText = data.tem_night
|
||||
tem_day.innerText = data.tem_day
|
||||
win.innerText = data.win
|
||||
win_speed.innerText = data.win_speed
|
||||
})
|
||||
.catch(console.error)
|
||||
|
||||
//获取时间
|
||||
var t = null;
|
||||
t = setTimeout(time, 1000);
|
||||
|
||||
function time() {
|
||||
clearTimeout(t);
|
||||
dt = new Date();
|
||||
var y = dt.getYear() + 1900;
|
||||
var mm = dt.getMonth() + 1;
|
||||
var d = dt.getDate();
|
||||
var weekday = ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"];
|
||||
var day = dt.getDay();
|
||||
var h = dt.getHours();
|
||||
var m = dt.getMinutes();
|
||||
var s = dt.getSeconds();
|
||||
if (h < 10) {
|
||||
h = "0" + h;
|
||||
}
|
||||
if (m < 10) {
|
||||
m = "0" + m;
|
||||
}
|
||||
if (s < 10) {
|
||||
s = "0" + s;
|
||||
}
|
||||
document.getElementById("time").innerHTML = y + " 年 " + mm + " 月 " + d + " 日 " + "<span class='weekday'>" + weekday[day] + "</span><br>" + "<span class='time-text'>" + h + ":" + m + ":" + s + "</span>";
|
||||
t = setTimeout(time, 1000);
|
||||
}
|
||||
|
||||
//必应壁纸
|
||||
var url = 'https://bird.ioliu.cn/v1/?url=https://www.bing.com/HPImageArchive.aspx?format=js&idx=0&n=8';
|
||||
var imgUrls = JSON.parse(sessionStorage.getItem("imgUrls"));
|
||||
var index = sessionStorage.getItem("index");
|
||||
var $section = $('#section');
|
||||
if (imgUrls == null) {
|
||||
imgUrls = new Array();
|
||||
index = 0;
|
||||
$.get(url, function (result) {
|
||||
images = result.images;
|
||||
for (let i = 0; i < images.length; i++) {
|
||||
const item = images[i];
|
||||
imgUrls.push(item.url);
|
||||
}
|
||||
var imgUrl = imgUrls[index];
|
||||
var url = "https://www.bing.com" + imgUrl;
|
||||
$section.css("background", "url('" + url + "') center center no-repeat #666");
|
||||
$section.css("background-size", "cover");
|
||||
sessionStorage.setItem("imgUrls", JSON.stringify(imgUrls));
|
||||
sessionStorage.setItem("index", index);
|
||||
});
|
||||
} else {
|
||||
if (index == 7)
|
||||
index = 0;
|
||||
else
|
||||
index++;
|
||||
var imgUrl = imgUrls[index];
|
||||
var url = "https://www.bing.com" + imgUrl;
|
||||
$section.css("background", "url('" + url + "') center center no-repeat #666");
|
||||
$section.css("background-size", "cover");
|
||||
sessionStorage.setItem("index", index);
|
||||
}
|
||||
|
||||
//加载动画
|
||||
window.addEventListener('load', function () {
|
||||
document.body.style.overflow = 'auto';
|
||||
document.getElementById('loading-box').classList.add("loaded")
|
||||
}, false)
|
||||
|
||||
//链接提示文字
|
||||
window.onload = function () {
|
||||
var link = document.getElementById("social");
|
||||
link.onmouseover = function () {
|
||||
document.getElementById("social").style.cssText = "background: rgb(0 0 0 / 25%);backdrop-filter: blur(5px);border-radius: 6px;transition: all 0.5s";
|
||||
document.getElementById("link-text").style.cssText = "display: block;transition: all 0.5s";
|
||||
};
|
||||
link.onmouseout = function () {
|
||||
document.getElementById("social").style.cssText = "background: none;backdrop-filter: none;border-radius: 6px;transition: all 0.5s";
|
||||
document.getElementById("link-text").style.cssText = "display: none;transition: all 0.5s";
|
||||
}
|
||||
|
||||
var link = document.getElementById("github");
|
||||
link.onmouseover = function () {
|
||||
document.getElementById("link-text").innerHTML = "去 Github 看看";
|
||||
};
|
||||
link.onmouseout = function () {
|
||||
document.getElementById("link-text").innerHTML = "通过这里联系我";
|
||||
}
|
||||
var link1 = document.getElementById("qq");
|
||||
link1.onmouseover = function () {
|
||||
document.getElementById("link-text").innerHTML = "有什么事吗";
|
||||
};
|
||||
link1.onmouseout = function () {
|
||||
document.getElementById("link-text").innerHTML = "通过这里联系我";
|
||||
}
|
||||
var link2 = document.getElementById("email");
|
||||
link2.onmouseover = function () {
|
||||
document.getElementById("link-text").innerHTML = "来封 Email";
|
||||
};
|
||||
link2.onmouseout = function () {
|
||||
document.getElementById("link-text").innerHTML = "通过这里联系我";
|
||||
}
|
||||
var link3 = document.getElementById("telegram");
|
||||
link3.onmouseover = function () {
|
||||
document.getElementById("link-text").innerHTML = "你懂的 ~";
|
||||
};
|
||||
link3.onmouseout = function () {
|
||||
document.getElementById("link-text").innerHTML = "通过这里联系我";
|
||||
}
|
||||
var link4 = document.getElementById("twitter");
|
||||
link4.onmouseover = function () {
|
||||
document.getElementById("link-text").innerHTML = "你懂的 ~";
|
||||
};
|
||||
link4.onmouseout = function () {
|
||||
document.getElementById("link-text").innerHTML = "通过这里联系我";
|
||||
}
|
||||
};
|
||||
|
||||
//菜单栏切换
|
||||
function switchMenu() {
|
||||
var menu = document.cookie.replace(/(?:(?:^|.*;\s*)menu\s*\=\s*([^;]*).*$)|^.*$/, "$1") || '0';
|
||||
if (menu == '0') {
|
||||
document.getElementById("container").classList.add('menus');
|
||||
document.getElementById("menu").innerHTML = "<i class='fad fa-times'></i>";
|
||||
document.cookie = "menu=1;path=/";
|
||||
} else {
|
||||
document.getElementById("container").classList.remove('menus');
|
||||
document.getElementById("menu").innerHTML = "<i class='fad fa-bars'></i>";
|
||||
document.cookie = "menu=0;path=/";
|
||||
}
|
||||
}
|
||||
|
||||
//更多页面切换
|
||||
function switchMore() {
|
||||
var more = document.cookie.replace(/(?:(?:^|.*;\s*)more\s*\=\s*([^;]*).*$)|^.*$/, "$1") || '0';
|
||||
if (more == '0') {
|
||||
document.getElementById("container").classList.add('mores');
|
||||
document.getElementById("change").innerHTML = "Oops !";
|
||||
document.getElementById("change1").innerHTML = "哎呀,这都被你发现了( 再点击一次可关闭 )";
|
||||
document.cookie = "more=1;path=/";
|
||||
} else {
|
||||
document.getElementById("container").classList.remove('mores');
|
||||
document.getElementById("change").innerHTML = "Hello World !";
|
||||
document.getElementById("change1").innerHTML = "一个建立于 21 世纪的小站,存活于互联网的边缘";
|
||||
document.cookie = "more=0;path=/";
|
||||
}
|
||||
}
|
||||
|
||||
//监听网页宽度
|
||||
window.addEventListener('load', function () {
|
||||
//console.log(window.innerWidth);
|
||||
window.addEventListener('resize', function () {
|
||||
//console.log(window.innerWidth);
|
||||
//关闭移动端样式
|
||||
if (window.innerWidth >= 600) {
|
||||
document.getElementById("container").classList.remove('menus');
|
||||
}
|
||||
//移动端隐藏更多页面
|
||||
if (window.innerWidth <= 990) {
|
||||
document.getElementById("container").classList.remove('mores');
|
||||
document.getElementById("change").innerHTML = "Hello World !";
|
||||
document.getElementById("change1").innerHTML = "一个建立于 21 世纪的小站,存活于互联网的边缘";
|
||||
}
|
||||
})
|
||||
|
||||
})
|
73
js/time.js
@ -1,73 +0,0 @@
|
||||
var vm = new Vue({
|
||||
el: '#date',
|
||||
data: {
|
||||
hour: "",
|
||||
week: "",
|
||||
curweek: "",
|
||||
day: "",
|
||||
curday: "",
|
||||
month: "",
|
||||
outday: "",
|
||||
},
|
||||
created: function () { //这里是定时器
|
||||
this.timer();
|
||||
setInterval(this.timer, 60000);
|
||||
},
|
||||
methods: {
|
||||
timer: function () {
|
||||
var myDate = new Date();
|
||||
var myYear = myDate.getFullYear(); // 获取当前年份
|
||||
var myMonth = myDate.getMonth() + 1; // 获取当前月份
|
||||
var myDay = myDate.getDate(); // 获取当前日(1- 31)
|
||||
var myHours = myDate.getHours(); // 获取当前小时(0-23)
|
||||
var myMinu = myDate.getMinutes(); // 获取当前分钟(0-59)
|
||||
var mySec = myDate.getSeconds(); // 获取当前秒数(0-59)
|
||||
var myWeek = myDate.getDay() + 6; //获取当前星期几(0-6)
|
||||
|
||||
this.hour = myHours;
|
||||
this.year = myYear;
|
||||
this.month = myMonth - 1;
|
||||
this.day = myDay - 1;
|
||||
this.curday = myDay;
|
||||
this.week = myWeek;
|
||||
this.curweek = myWeek + 1;
|
||||
this.minute = myMinu;
|
||||
this.age = myYear - this.yearForYour;
|
||||
},
|
||||
//今天
|
||||
jinduT: function () {
|
||||
var tian = ((this.hour * 60 + this.minute) / 24 / 60 * 100).toFixed(1);
|
||||
return "<div class='progress'><div class='progress-bar' style='width:" + tian + "%'>" + tian + " %" +
|
||||
"</div></div>";
|
||||
},
|
||||
//本周
|
||||
jinduZ: function () {
|
||||
var curdayWithHour = (this.week * 24 * 60 + this.hour * 60 + this.minute) / 7 / 24 / 60;
|
||||
var zhou = (curdayWithHour * 100).toFixed(1);
|
||||
return "<div class='progress'><div class='progress-bar' style='width:" + zhou + "%'>" + zhou + " %" +
|
||||
"</div></div>";
|
||||
},
|
||||
//这个月
|
||||
jinduD: function () {
|
||||
var days = new Date(this.year, this.month + 1, 0).getDate();
|
||||
var yue = ((this.day * 24 * 60 + this.hour * 60 + this.minute) / days / 24 / 60 * 100)
|
||||
.toFixed(1);
|
||||
return "<div class='progress'><div class='progress-bar" + "' style='width:" + yue +
|
||||
"%'>" + yue + " %" + "</div></div>";
|
||||
},
|
||||
//年
|
||||
jinduY: function () {
|
||||
var olddate = new Date(this.year, 0);
|
||||
var nowdate = new Date(this.year, this.month, this.day + 1);
|
||||
var outday = (nowdate - olddate) / (1000 * 60 * 60 * 24) + 1; //
|
||||
this.outday = outday; //已经过去天数
|
||||
var isLeap = (0 === this.year % 4) && (0 === this.year % 100) || (0 === this.year %
|
||||
400);
|
||||
var days = isLeap ? 366 : 365; //今年的天数
|
||||
var ye = (((outday - 1) * 24 * 60 + this.hour * 60 + this.minute) / days / 24 / 60 *
|
||||
100).toFixed(1);
|
||||
return "<div class='progress'><div class='progress-bar" + "' style='width:" + ye +
|
||||
"%'>" + ye + " %" + "</div></div>";
|
||||
}
|
||||
}
|
||||
})
|
44
package.json
Normal file
@ -0,0 +1,44 @@
|
||||
{
|
||||
"name": "home",
|
||||
"author": "imsyy",
|
||||
"github": "https://github.com/imsyy/home",
|
||||
"home": "https://imsyy.top",
|
||||
"private": true,
|
||||
"version": "4.1.4",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite --host",
|
||||
"build": "vite build",
|
||||
"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.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.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.7"
|
||||
}
|
||||
}
|
5112
pnpm-lock.yaml
Normal file
BIN
public/font/Pacifico-Regular.ttf
Normal file
3
public/font/README.md
Normal file
@ -0,0 +1,3 @@
|
||||
## Logo 字体替换
|
||||
|
||||
可将该文件夹下的 `Pacifico-Regular-all.ttf` 替换原来的 `Pacifico-Regular.ttf`
|
BIN
public/images/background1.jpg
Normal file
After Width: | Height: | Size: 51 KiB |
BIN
public/images/background10.jpg
Normal file
After Width: | Height: | Size: 41 KiB |
BIN
public/images/background2.jpg
Normal file
After Width: | Height: | Size: 93 KiB |
BIN
public/images/background3.jpg
Normal file
After Width: | Height: | Size: 36 KiB |
BIN
public/images/background4.jpg
Normal file
After Width: | Height: | Size: 95 KiB |
BIN
public/images/background5.jpg
Normal file
After Width: | Height: | Size: 138 KiB |
BIN
public/images/background6.jpg
Normal file
After Width: | Height: | Size: 33 KiB |
BIN
public/images/background7.jpg
Normal file
After Width: | Height: | Size: 36 KiB |
BIN
public/images/background8.jpg
Normal file
After Width: | Height: | Size: 92 KiB |
BIN
public/images/background9.jpg
Normal file
After Width: | Height: | Size: 56 KiB |
BIN
public/images/icon/128.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
public/images/icon/144.png
Normal file
After Width: | Height: | Size: 2.1 KiB |
BIN
public/images/icon/180.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
public/images/icon/192.png
Normal file
After Width: | Height: | Size: 3.0 KiB |
BIN
public/images/icon/32.png
Normal file
After Width: | Height: | Size: 2.4 KiB |
BIN
public/images/icon/48.png
Normal file
After Width: | Height: | Size: 4.6 KiB |
BIN
public/images/icon/512.png
Normal file
After Width: | Height: | Size: 8.9 KiB |
BIN
public/images/icon/72.png
Normal file
After Width: | Height: | Size: 7.7 KiB |
BIN
public/images/icon/96.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 5.1 KiB After Width: | Height: | Size: 5.1 KiB |
BIN
public/images/icon/bilibili.png
Normal file
After Width: | Height: | Size: 3.8 KiB |
BIN
public/images/icon/candle.png
Normal file
After Width: | Height: | Size: 5.4 KiB |
BIN
public/images/icon/email.png
Normal file
After Width: | Height: | Size: 3.7 KiB |
Before Width: | Height: | Size: 264 KiB After Width: | Height: | Size: 264 KiB |
BIN
public/images/icon/gitee.png
Normal file
After Width: | Height: | Size: 3.2 KiB |
BIN
public/images/icon/github.png
Normal file
After Width: | Height: | Size: 4.1 KiB |
Before Width: | Height: | Size: 5.1 KiB After Width: | Height: | Size: 5.1 KiB |
BIN
public/images/icon/music.png
Normal file
After Width: | Height: | Size: 4.6 KiB |
BIN
public/images/icon/pause.png
Normal file
After Width: | Height: | Size: 4.0 KiB |
BIN
public/images/icon/play.png
Normal file
After Width: | Height: | Size: 4.0 KiB |
BIN
public/images/icon/qq.png
Normal file
After Width: | Height: | Size: 3.8 KiB |
BIN
public/images/icon/telegram.png
Normal file
After Width: | Height: | Size: 3.7 KiB |
BIN
public/images/icon/twitter.png
Normal file
After Width: | Height: | Size: 4.1 KiB |
BIN
public/images/icon/warn.png
Normal file
After Width: | Height: | Size: 6.2 KiB |
BIN
screenshots/main.jpg
Normal file
After Width: | Height: | Size: 245 KiB |
BIN
screenshots/step1.jpg
Normal file
After Width: | Height: | Size: 56 KiB |
BIN
screenshots/step2.jpg
Normal file
After Width: | Height: | Size: 67 KiB |
191
src/App.vue
Normal file
@ -0,0 +1,191 @@
|
||||
<template>
|
||||
<!-- 加载 -->
|
||||
<Loading />
|
||||
<!-- 壁纸 -->
|
||||
<Background @loadComplete="loadComplete" />
|
||||
<!-- 主界面 -->
|
||||
<Transition name="fade" mode="out-in">
|
||||
<main id="main" v-if="store.imgLoadStatus">
|
||||
<div class="container" v-show="!store.backgroundShow">
|
||||
<section class="all" v-show="!store.setOpenState">
|
||||
<MainLeft />
|
||||
<MainRight v-show="!store.boxOpenState" />
|
||||
<Box v-show="store.boxOpenState" />
|
||||
</section>
|
||||
<section class="more" v-show="store.setOpenState" @click="store.setOpenState = false">
|
||||
<MoreSet />
|
||||
</section>
|
||||
</div>
|
||||
<!-- 移动端菜单按钮 -->
|
||||
<Icon
|
||||
class="menu"
|
||||
size="24"
|
||||
v-show="!store.backgroundShow"
|
||||
@click="store.mobileOpenState = !store.mobileOpenState"
|
||||
>
|
||||
<component :is="store.mobileOpenState ? CloseSmall : HamburgerButton" />
|
||||
</Icon>
|
||||
<!-- 页脚 -->
|
||||
<Transition name="fade" mode="out-in">
|
||||
<Footer v-show="!store.backgroundShow && !store.setOpenState" />
|
||||
</Transition>
|
||||
</main>
|
||||
</Transition>
|
||||
</template>
|
||||
<script setup>
|
||||
import { helloInit, checkDays } from "@/utils/getTime.js";
|
||||
import { HamburgerButton, CloseSmall } from "@icon-park/vue-next";
|
||||
import { mainStore } from "@/store";
|
||||
import { Icon } from "@vicons/utils";
|
||||
import Loading from "@/components/Loading.vue";
|
||||
import MainLeft from "@/views/Main/Left.vue";
|
||||
import MainRight from "@/views/Main/Right.vue";
|
||||
import Background from "@/components/Background.vue";
|
||||
import Footer from "@/components/Footer.vue";
|
||||
import Box from "@/views/Box/index.vue";
|
||||
import MoreSet from "@/views/MoreSet/index.vue";
|
||||
import cursorInit from "@/utils/cursor.js";
|
||||
import config from "@/../package.json";
|
||||
|
||||
const store = mainStore();
|
||||
|
||||
// 页面宽度
|
||||
const getWidth = () => {
|
||||
store.setInnerWidth(window.innerWidth);
|
||||
};
|
||||
|
||||
// 加载完成事件
|
||||
const loadComplete = () => {
|
||||
nextTick(() => {
|
||||
// 欢迎提示
|
||||
helloInit();
|
||||
// 默哀模式
|
||||
checkDays();
|
||||
});
|
||||
};
|
||||
|
||||
// 监听宽度变化
|
||||
watch(
|
||||
() => store.innerWidth,
|
||||
(value) => {
|
||||
if (value < 990) {
|
||||
store.boxOpenState = false;
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
onMounted(() => {
|
||||
// 自定义鼠标
|
||||
cursorInit();
|
||||
|
||||
// 屏蔽右键
|
||||
document.oncontextmenu = () => {
|
||||
ElMessage({
|
||||
message: "为了浏览体验,本站禁用右键",
|
||||
grouping: true,
|
||||
duration: 2000,
|
||||
});
|
||||
return false;
|
||||
};
|
||||
|
||||
// 鼠标中键事件
|
||||
window.addEventListener("mousedown", (event) => {
|
||||
if (event.button == 1) {
|
||||
store.backgroundShow = !store.backgroundShow;
|
||||
ElMessage({
|
||||
message: `已${store.backgroundShow ? "开启" : "退出"}壁纸展示状态`,
|
||||
grouping: true,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 监听当前页面宽度
|
||||
getWidth();
|
||||
window.addEventListener("resize", getWidth);
|
||||
|
||||
// 控制台输出
|
||||
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 = "無名の主页";
|
||||
const title2 = `
|
||||
_____ __ __ _______ ____ __
|
||||
|_ _| \\/ |/ ____\\ \\ / /\\ \\ / /
|
||||
| | | \\ / | (___ \\ \\_/ / \\ \\_/ /
|
||||
| | | |\\/| |\\___ \\ \\ / \\ /
|
||||
_| |_| | | |____) | | | | |
|
||||
|_____|_| |_|_____/ |_| |_|`;
|
||||
const content = `\n\n版本: ${config.version}\n主页: ${config.home}\nGithub: ${config.github}`;
|
||||
console.info(`%c${title1} %c${title2} %c${content}`, styleTitle1, styleTitle2, styleContent);
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
window.removeEventListener("resize", getWidth);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
#main {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
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-delay: 0.5s;
|
||||
.container {
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
margin: 0 auto;
|
||||
.all {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 0 0.75rem;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
.more {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: #00000080;
|
||||
backdrop-filter: blur(20px);
|
||||
z-index: 2;
|
||||
animation: fade 0.5s;
|
||||
}
|
||||
@media (max-width: 1200px) {
|
||||
padding: 0 2vw;
|
||||
}
|
||||
}
|
||||
.menu {
|
||||
position: fixed;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
top: 84%;
|
||||
left: calc(50% - 28px);
|
||||
width: 56px;
|
||||
height: 34px;
|
||||
background: rgb(0 0 0 / 20%);
|
||||
backdrop-filter: blur(10px);
|
||||
border-radius: 6px;
|
||||
transition: transform 0.3s;
|
||||
animation: fade 0.5s;
|
||||
&:active {
|
||||
transform: scale(0.95);
|
||||
}
|
||||
.i-icon {
|
||||
transform: translateY(2px);
|
||||
}
|
||||
@media (min-width: 721px) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
75
src/api/index.js
Normal file
@ -0,0 +1,75 @@
|
||||
// import axios from "axios";
|
||||
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}`,
|
||||
);
|
||||
const data = await res.json();
|
||||
|
||||
if (data[0].url.startsWith("@")) {
|
||||
// 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")) ||
|
||||
jsonpData.req_0.data.sip[0]
|
||||
).replace("http://", "https://");
|
||||
|
||||
return data.map((v, i) => ({
|
||||
name: v.name || v.title,
|
||||
artist: v.artist || v.author,
|
||||
url: domain + jsonpData.req_0.data.midurlinfo[i].purl,
|
||||
cover: v.cover || v.pic,
|
||||
lrc: v.lrc,
|
||||
}));
|
||||
} else {
|
||||
return data.map((v) => ({
|
||||
name: v.name || v.title,
|
||||
artist: v.artist || v.author,
|
||||
url: v.url,
|
||||
cover: v.cover || v.pic,
|
||||
lrc: v.lrc,
|
||||
}));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 一言
|
||||
*/
|
||||
|
||||
// 获取一言数据
|
||||
export const getHitokoto = async () => {
|
||||
const res = await fetch("https://v1.hitokoto.cn");
|
||||
return await res.json();
|
||||
};
|
||||
|
||||
/**
|
||||
* 天气
|
||||
*/
|
||||
|
||||
// 获取高德地理位置信息
|
||||
export const getAdcode = async (key) => {
|
||||
const res = await fetch(`https://restapi.amap.com/v3/ip?key=${key}`);
|
||||
return await res.json();
|
||||
};
|
||||
|
||||
// 获取高德地理天气信息
|
||||
export const getWeather = async (key, city) => {
|
||||
const res = await fetch(
|
||||
`https://restapi.amap.com/v3/weather/weatherInfo?key=${key}&city=${city}`,
|
||||
);
|
||||
return await res.json();
|
||||
};
|
||||
|
||||
// 获取教书先生天气 API
|
||||
// https://api.oioweb.cn/doc/weather/GetWeather
|
||||
export const getOtherWeather = async () => {
|
||||
const res = await fetch("https://api.oioweb.cn/api/weather/GetWeather");
|
||||
return await res.json();
|
||||
};
|
37
src/assets/siteLinks.json
Normal file
@ -0,0 +1,37 @@
|
||||
[
|
||||
{
|
||||
"icon": "Blog",
|
||||
"name": "博客",
|
||||
"link": "https://blog.imsyy.top/"
|
||||
},
|
||||
{
|
||||
"icon": "Cloud",
|
||||
"name": "网盘",
|
||||
"link": "https://pan.imsyy.top/"
|
||||
},
|
||||
{
|
||||
"icon": "CompactDisc",
|
||||
"name": "音乐",
|
||||
"link": "https://music.imsyy.top/"
|
||||
},
|
||||
{
|
||||
"icon": "Compass",
|
||||
"name": "起始页",
|
||||
"link": "https://nav.imsyy.top/"
|
||||
},
|
||||
{
|
||||
"icon": "Book",
|
||||
"name": "网址集",
|
||||
"link": "https://web.imsyy.top/"
|
||||
},
|
||||
{
|
||||
"icon": "Fire",
|
||||
"name": "今日热榜",
|
||||
"link": "https://hot.imsyy.top/"
|
||||
},
|
||||
{
|
||||
"icon": "LaptopCode",
|
||||
"name": "站点监测",
|
||||
"link": "https://status.imsyy.top/"
|
||||
}
|
||||
]
|
38
src/assets/socialLinks.json
Normal file
@ -0,0 +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"
|
||||
}
|
||||
]
|
171
src/components/Background.vue
Normal file
@ -0,0 +1,171 @@
|
||||
<template>
|
||||
<div :class="store.backgroundShow ? 'cover show' : 'cover'">
|
||||
<img
|
||||
v-show="store.imgLoadStatus"
|
||||
:src="bgUrl"
|
||||
class="bg"
|
||||
alt="cover"
|
||||
@load="imgLoadComplete"
|
||||
@error.once="imgLoadError"
|
||||
@animationend="imgAnimationEnd"
|
||||
/>
|
||||
<div :class="store.backgroundShow ? 'gray hidden' : 'gray'" />
|
||||
<Transition name="fade" mode="out-in">
|
||||
<a
|
||||
v-if="store.backgroundShow && store.coverType != '3'"
|
||||
class="down"
|
||||
:href="bgUrl"
|
||||
target="_blank"
|
||||
>
|
||||
下载壁纸
|
||||
</a>
|
||||
</Transition>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { mainStore } from "@/store";
|
||||
import { Error } from "@icon-park/vue-next";
|
||||
|
||||
const store = mainStore();
|
||||
const bgUrl = ref(null);
|
||||
const imgTimeout = ref(null);
|
||||
const emit = defineEmits(["loadComplete"]);
|
||||
|
||||
// 壁纸随机数
|
||||
// 请依据文件夹内的图片个数修改 Math.random() 后面的第一个数字
|
||||
const bgRandom = Math.floor(Math.random() * 10 + 1);
|
||||
|
||||
// 更换壁纸链接
|
||||
const changeBg = (type) => {
|
||||
if (type == 0) {
|
||||
bgUrl.value = `/images/background${bgRandom}.jpg`;
|
||||
} else if (type == 1) {
|
||||
bgUrl.value = "https://api.dujin.org/bing/1920.php";
|
||||
} else if (type == 2) {
|
||||
bgUrl.value = "https://api.vvhan.com/api/wallpaper/views";
|
||||
} else if (type == 3) {
|
||||
bgUrl.value = "https://api.vvhan.com/api/wallpaper/acg";
|
||||
}
|
||||
};
|
||||
|
||||
// 图片加载完成
|
||||
const imgLoadComplete = () => {
|
||||
imgTimeout.value = setTimeout(
|
||||
() => {
|
||||
store.setImgLoadStatus(true);
|
||||
},
|
||||
Math.floor(Math.random() * (600 - 300 + 1)) + 300,
|
||||
);
|
||||
};
|
||||
|
||||
// 图片动画完成
|
||||
const imgAnimationEnd = () => {
|
||||
console.log("壁纸加载且动画完成");
|
||||
// 加载完成事件
|
||||
emit("loadComplete");
|
||||
};
|
||||
|
||||
// 图片显示失败
|
||||
const imgLoadError = () => {
|
||||
console.error("壁纸加载失败:", bgUrl.value);
|
||||
ElMessage({
|
||||
message: "壁纸加载失败,已临时切换回默认",
|
||||
icon: h(Error, {
|
||||
theme: "filled",
|
||||
fill: "#efefef",
|
||||
}),
|
||||
});
|
||||
bgUrl.value = `/images/background${bgRandom}.jpg`;
|
||||
};
|
||||
|
||||
// 监听壁纸切换
|
||||
watch(
|
||||
() => store.coverType,
|
||||
(value) => {
|
||||
changeBg(value);
|
||||
},
|
||||
);
|
||||
|
||||
onMounted(() => {
|
||||
// 加载壁纸
|
||||
changeBg(store.coverType);
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
clearTimeout(imgTimeout.value);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.cover {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
transition: 0.25s;
|
||||
z-index: -1;
|
||||
|
||||
&.show {
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.bg {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
backface-visibility: hidden;
|
||||
filter: blur(20px) brightness(0.3);
|
||||
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 {
|
||||
opacity: 1;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 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;
|
||||
&.hidden {
|
||||
opacity: 0;
|
||||
transition: 1.5s;
|
||||
}
|
||||
}
|
||||
.down {
|
||||
font-size: 16px;
|
||||
color: white;
|
||||
position: absolute;
|
||||
bottom: 30px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
margin: 0 auto;
|
||||
display: block;
|
||||
padding: 20px 26px;
|
||||
border-radius: 8px;
|
||||
background-color: #00000030;
|
||||
width: 120px;
|
||||
height: 30px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
&:hover {
|
||||
transform: scale(1.05);
|
||||
background-color: #00000060;
|
||||
}
|
||||
&:active {
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
120
src/components/Footer.vue
Normal file
@ -0,0 +1,120 @@
|
||||
<template>
|
||||
<footer id="footer" :class="store.footerBlur ? 'blur' : null">
|
||||
<Transition name="fade" mode="out-in">
|
||||
<div v-if="!store.playerState || !store.playerLrcShow" class="power">
|
||||
<span>
|
||||
Copyright ©
|
||||
<span v-if="siteStartDate?.length >= 4" class="site-start">
|
||||
{{ siteStartDate.substring(0, 4) }}
|
||||
-
|
||||
</span>
|
||||
{{ fullYear }}
|
||||
<a :href="siteUrl">{{ siteAnthor }}</a>
|
||||
</span>
|
||||
<!-- 以下信息请不要修改哦 -->
|
||||
<span class="hidden">
|
||||
& Made by
|
||||
<a :href="config.github" target="_blank">
|
||||
{{ config.author }}
|
||||
</a>
|
||||
</span>
|
||||
<!-- 站点备案 -->
|
||||
<a v-if="siteIcp" href="https://beian.miit.gov.cn" target="_blank">
|
||||
&
|
||||
{{ siteIcp }}
|
||||
</a>
|
||||
</div>
|
||||
<div v-else class="lrc">
|
||||
<Transition name="fade" mode="out-in">
|
||||
<div class="lrc-all" :key="store.getPlayerLrc">
|
||||
<music-one theme="filled" size="18" fill="#efefef" />
|
||||
<span class="lrc-text text-hidden" v-html="store.getPlayerLrc" />
|
||||
<music-one theme="filled" size="18" fill="#efefef" />
|
||||
</div>
|
||||
</Transition>
|
||||
</div>
|
||||
</Transition>
|
||||
</footer>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { MusicOne } from "@icon-park/vue-next";
|
||||
import { mainStore } from "@/store";
|
||||
import config from "@/../package.json";
|
||||
|
||||
const store = mainStore();
|
||||
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 = 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>
|
||||
#footer {
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
height: 46px;
|
||||
line-height: 46px;
|
||||
text-align: center;
|
||||
z-index: 0;
|
||||
font-size: 14px;
|
||||
.power {
|
||||
animation: fade 0.3s;
|
||||
}
|
||||
.lrc {
|
||||
padding: 0 20px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
.lrc-all {
|
||||
width: 98%;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
.lrc-text {
|
||||
margin: 0 8px;
|
||||
}
|
||||
.i-icon {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
display: inherit;
|
||||
}
|
||||
}
|
||||
}
|
||||
&.blur {
|
||||
backdrop-filter: blur(10px);
|
||||
background: rgb(0 0 0 / 25%);
|
||||
font-size: 16px;
|
||||
}
|
||||
.fade-enter-active,
|
||||
.fade-leave-active {
|
||||
transition: opacity 0.15s ease-in-out;
|
||||
}
|
||||
@media (max-width: 720px) {
|
||||
font-size: 0.85rem;
|
||||
&.blur {
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
}
|
||||
@media (max-width: 480px) {
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
128
src/components/Hitokoto.vue
Normal file
@ -0,0 +1,128 @@
|
||||
<template>
|
||||
<div
|
||||
class="hitokoto cards"
|
||||
v-show="!store.musicOpenState"
|
||||
@mouseenter="openMusicShow = true"
|
||||
@mouseleave="openMusicShow = false"
|
||||
@click.stop
|
||||
>
|
||||
<!-- 打开音乐面板 -->
|
||||
<Transition name="el-fade-in-linear">
|
||||
<div
|
||||
class="open-music"
|
||||
v-show="openMusicShow && store.musicIsOk"
|
||||
@click="store.musicOpenState = true"
|
||||
>
|
||||
<music-menu theme="filled" size="18" fill="#efefef" />
|
||||
<span>打开音乐播放器</span>
|
||||
</div>
|
||||
</Transition>
|
||||
<!-- 一言内容 -->
|
||||
<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>
|
||||
|
||||
<script setup>
|
||||
import { MusicMenu, Error } from "@icon-park/vue-next";
|
||||
import { getHitokoto } from "@/api";
|
||||
import { mainStore } from "@/store";
|
||||
import debounce from "@/utils/debounce.js";
|
||||
|
||||
const store = mainStore();
|
||||
|
||||
// 开启音乐面板按钮显隐
|
||||
const openMusicShow = ref(false);
|
||||
|
||||
// 一言数据
|
||||
const hitokotoData = reactive({
|
||||
text: "这里应该显示一句话",
|
||||
from: "無名",
|
||||
});
|
||||
|
||||
// 获取一言数据
|
||||
const getHitokotoData = async () => {
|
||||
try {
|
||||
const result = await getHitokoto();
|
||||
hitokotoData.text = result.hitokoto;
|
||||
hitokotoData.from = result.from;
|
||||
} catch (error) {
|
||||
ElMessage({
|
||||
message: "一言获取失败",
|
||||
icon: h(Error, {
|
||||
theme: "filled",
|
||||
fill: "#efefef",
|
||||
}),
|
||||
});
|
||||
hitokotoData.text = "这里应该显示一句话";
|
||||
hitokotoData.from = "無名";
|
||||
}
|
||||
};
|
||||
|
||||
// 更新一言数据
|
||||
const updateHitokoto = () => {
|
||||
// 防抖
|
||||
debounce(() => {
|
||||
getHitokotoData();
|
||||
}, 500);
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
getHitokotoData();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.hitokoto {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 20px;
|
||||
animation: fade 0.5s;
|
||||
.open-music {
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: #00000026;
|
||||
padding: 4px 0;
|
||||
border-radius: 8px 8px 0 0;
|
||||
.i-icon {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
display: block;
|
||||
margin-right: 8px;
|
||||
}
|
||||
span {
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
}
|
||||
.content {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-evenly;
|
||||
.text {
|
||||
font-size: 1.1rem;
|
||||
word-break: break-all;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 3;
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
.from {
|
||||
margin-top: 10px;
|
||||
font-weight: bold;
|
||||
align-self: flex-end;
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
182
src/components/Links.vue
Normal file
@ -0,0 +1,182 @@
|
||||
<template>
|
||||
<div v-if="siteLinks[0]" class="links">
|
||||
<div class="line">
|
||||
<Icon size="20">
|
||||
<Link />
|
||||
</Icon>
|
||||
<span class="title">网站列表</span>
|
||||
</div>
|
||||
<!-- 网站列表 -->
|
||||
<Swiper
|
||||
v-if="siteLinks[0]"
|
||||
:modules="[Pagination, Mousewheel]"
|
||||
:slides-per-view="1"
|
||||
:space-between="40"
|
||||
:pagination="{
|
||||
el: '.swiper-pagination',
|
||||
clickable: true,
|
||||
bulletElement: 'div',
|
||||
}"
|
||||
:mousewheel="true"
|
||||
>
|
||||
<SwiperSlide v-for="site in siteLinksList" :key="site">
|
||||
<el-row class="link-all" :gutter="20">
|
||||
<el-col v-for="(item, index) in site" :span="8" :key="item">
|
||||
<div
|
||||
class="item cards"
|
||||
:style="index < 3 ? 'margin-bottom: 20px' : null"
|
||||
@click="jumpLink(item)"
|
||||
>
|
||||
<Icon size="26">
|
||||
<component :is="siteIcon[item.icon]" />
|
||||
</Icon>
|
||||
<span class="name text-hidden">{{ item.name }}</span>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</SwiperSlide>
|
||||
<div class="swiper-pagination" />
|
||||
</Swiper>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { Icon } from "@vicons/utils";
|
||||
// 可前往 https://www.xicons.org 自行挑选并在此处引入
|
||||
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/modules";
|
||||
import siteLinks from "@/assets/siteLinks.json";
|
||||
|
||||
const store = mainStore();
|
||||
|
||||
// 计算网站链接
|
||||
const siteLinksList = computed(() => {
|
||||
const result = [];
|
||||
for (let i = 0; i < siteLinks.length; i += 6) {
|
||||
const subArr = siteLinks.slice(i, i + 6);
|
||||
result.push(subArr);
|
||||
}
|
||||
return result;
|
||||
});
|
||||
|
||||
// 网站链接图标
|
||||
const siteIcon = {
|
||||
Blog,
|
||||
Cloud,
|
||||
CompactDisc,
|
||||
Compass,
|
||||
Book,
|
||||
Fire,
|
||||
LaptopCode,
|
||||
};
|
||||
|
||||
// 链接跳转
|
||||
const jumpLink = (data) => {
|
||||
if (data.name === "音乐" && store.musicClick) {
|
||||
if (typeof $openList === "function") $openList();
|
||||
} else {
|
||||
window.open(data.link, "_blank");
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
console.log(siteLinks);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.links {
|
||||
.line {
|
||||
margin: 2rem 0.25rem 1rem;
|
||||
font-size: 1.1rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
animation: fade 0.5s;
|
||||
.title {
|
||||
margin-left: 8px;
|
||||
font-size: 1.15rem;
|
||||
text-shadow: 0 0 5px #00000050;
|
||||
}
|
||||
}
|
||||
.swiper {
|
||||
left: -10px;
|
||||
width: calc(100% + 20px);
|
||||
padding: 5px 10px 0;
|
||||
z-index: 0;
|
||||
.swiper-slide {
|
||||
height: 100%;
|
||||
}
|
||||
.swiper-pagination {
|
||||
margin-top: 12px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
:deep(.swiper-pagination-bullet) {
|
||||
background-color: #fff;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.link-all {
|
||||
height: 220px;
|
||||
.item {
|
||||
height: 100px;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
padding: 0 10px;
|
||||
animation: fade 0.5s;
|
||||
|
||||
&:hover {
|
||||
transform: scale(1.02);
|
||||
background: rgb(0 0 0 / 40%);
|
||||
transition: 0.3s;
|
||||
}
|
||||
|
||||
&:active {
|
||||
transform: scale(1);
|
||||
}
|
||||
|
||||
.name {
|
||||
font-size: 1.1rem;
|
||||
margin-left: 8px;
|
||||
}
|
||||
@media (min-width: 720px) and (max-width: 820px) {
|
||||
.name {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
@media (max-width: 720px) {
|
||||
height: 80px;
|
||||
}
|
||||
@media (max-width: 460px) {
|
||||
flex-direction: column;
|
||||
.name {
|
||||
font-size: 1rem;
|
||||
margin-left: 0;
|
||||
margin-top: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
@media (max-width: 720px) {
|
||||
height: 180px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
152
src/components/Loading.vue
Normal file
@ -0,0 +1,152 @@
|
||||
<template>
|
||||
<div id="loader-wrapper" :class="store.imgLoadStatus ? 'loaded' : null">
|
||||
<div class="loader">
|
||||
<div class="loader-circle" />
|
||||
<div class="loader-text">
|
||||
<span class="name">
|
||||
{{ siteName }}
|
||||
</span>
|
||||
<span class="tip"> 加载中 </span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="loader-section section-left" />
|
||||
<div class="loader-section section-right" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { mainStore } from "@/store";
|
||||
|
||||
const store = mainStore();
|
||||
|
||||
// 配置
|
||||
const siteName = import.meta.env.VITE_SITE_NAME;
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
#loader-wrapper {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 999;
|
||||
overflow: hidden;
|
||||
.loader {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
.loader-circle {
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
border-radius: 50%;
|
||||
border: 3px solid transparent;
|
||||
border-top-color: #fff;
|
||||
animation: spin 1.8s linear infinite;
|
||||
z-index: 2;
|
||||
|
||||
&:before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
left: 5px;
|
||||
right: 5px;
|
||||
bottom: 5px;
|
||||
border-radius: 50%;
|
||||
border: 3px solid transparent;
|
||||
border-top-color: #a4a4a4;
|
||||
animation: spin-reverse 0.6s linear infinite;
|
||||
}
|
||||
|
||||
&:after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 15px;
|
||||
left: 15px;
|
||||
right: 15px;
|
||||
bottom: 15px;
|
||||
border-radius: 50%;
|
||||
border: 3px solid transparent;
|
||||
border-top-color: #d3d3d3;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
}
|
||||
.loader-text {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
color: #fff;
|
||||
z-index: 2;
|
||||
margin-top: 40px;
|
||||
font-size: 24px;
|
||||
.tip {
|
||||
margin-top: 6px;
|
||||
font-size: 18px;
|
||||
opacity: 0.6;
|
||||
}
|
||||
}
|
||||
}
|
||||
.loader-section {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
width: 51%;
|
||||
height: 100%;
|
||||
background: #333;
|
||||
z-index: 1;
|
||||
&.section-left {
|
||||
left: 0;
|
||||
}
|
||||
&.section-right {
|
||||
right: 0;
|
||||
}
|
||||
}
|
||||
&.loaded {
|
||||
visibility: hidden;
|
||||
transform: translateY(-100%);
|
||||
transition:
|
||||
transform 0.3s 1s ease-out,
|
||||
visibility 0.3s 1s ease-out;
|
||||
.loader {
|
||||
.loader-circle,
|
||||
.loader-text {
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s ease-out;
|
||||
}
|
||||
}
|
||||
.loader-section {
|
||||
&.section-left {
|
||||
transform: translateX(-100%);
|
||||
transition: transform 0.5s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
|
||||
}
|
||||
&.section-right {
|
||||
transform: translateX(100%);
|
||||
transition: transform 0.5s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes spin-reverse {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
transform: rotate(-360deg);
|
||||
}
|
||||
}
|
||||
</style>
|
193
src/components/Message.vue
Normal file
@ -0,0 +1,193 @@
|
||||
<template>
|
||||
<!-- 基本信息 -->
|
||||
<div class="message">
|
||||
<!-- Logo -->
|
||||
<div class="logo">
|
||||
<img class="logo-img" :src="siteLogo" alt="logo" />
|
||||
<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>
|
||||
</div>
|
||||
<!-- 简介 -->
|
||||
<div class="description cards" @click="changeBox">
|
||||
<div class="content">
|
||||
<Icon size="16">
|
||||
<QuoteLeft />
|
||||
</Icon>
|
||||
<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>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { Icon } from "@vicons/utils";
|
||||
import { QuoteLeft, QuoteRight } from "@vicons/fa";
|
||||
import { Error } from "@icon-park/vue-next";
|
||||
import { mainStore } from "@/store";
|
||||
const store = mainStore();
|
||||
|
||||
// 主页站点logo
|
||||
const siteLogo = import.meta.env.VITE_SITE_MAIN_LOGO;
|
||||
// 站点链接
|
||||
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({
|
||||
hello: import.meta.env.VITE_DESC_HELLO,
|
||||
text: import.meta.env.VITE_DESC_TEXT,
|
||||
});
|
||||
|
||||
// 切换右侧功能区
|
||||
const changeBox = () => {
|
||||
if (store.getInnerWidth >= 990) {
|
||||
store.boxOpenState = !store.boxOpenState;
|
||||
} else {
|
||||
ElMessage({
|
||||
message: "当前页面宽度不足以开启盒子",
|
||||
grouping: true,
|
||||
icon: h(Error, {
|
||||
theme: "filled",
|
||||
fill: "#efefef",
|
||||
}),
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 监听状态变化
|
||||
watch(
|
||||
() => store.boxOpenState,
|
||||
(value) => {
|
||||
if (value) {
|
||||
descriptionText.hello = import.meta.env.VITE_DESC_HELLO_OTHER;
|
||||
descriptionText.text = import.meta.env.VITE_DESC_TEXT_OTHER;
|
||||
} else {
|
||||
descriptionText.hello = import.meta.env.VITE_DESC_HELLO;
|
||||
descriptionText.text = import.meta.env.VITE_DESC_TEXT;
|
||||
}
|
||||
},
|
||||
);
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.message {
|
||||
.logo {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
animation: fade 0.5s;
|
||||
max-width: 460px;
|
||||
.logo-img {
|
||||
border-radius: 50%;
|
||||
width: 120px;
|
||||
}
|
||||
.name {
|
||||
width: 100%;
|
||||
padding-left: 22px;
|
||||
transform: translateY(-8px);
|
||||
font-family: "Pacifico-Regular";
|
||||
|
||||
.bg {
|
||||
font-size: 5rem;
|
||||
}
|
||||
|
||||
.sm {
|
||||
margin-left: 6px;
|
||||
font-size: 2rem;
|
||||
@media (min-width: 720px) and (max-width: 789px) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
@media (max-width: 768px) {
|
||||
.logo-img {
|
||||
width: 100px;
|
||||
}
|
||||
.name {
|
||||
height: 128px;
|
||||
.bg {
|
||||
font-size: 4.5rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 720px) {
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.description {
|
||||
padding: 1rem;
|
||||
margin-top: 3.5rem;
|
||||
max-width: 460px;
|
||||
animation: fade 0.5s;
|
||||
|
||||
.content {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
.text {
|
||||
margin: 0.75rem 1rem;
|
||||
line-height: 2rem;
|
||||
margin-right: auto;
|
||||
transition: opacity 0.2s;
|
||||
|
||||
p {
|
||||
&:nth-of-type(1) {
|
||||
font-family: "Pacifico-Regular";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.xicon:nth-of-type(2) {
|
||||
align-self: flex-end;
|
||||
}
|
||||
}
|
||||
@media (max-width: 720px) {
|
||||
max-width: 100%;
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
@media (max-width: 390px) {
|
||||
.logo {
|
||||
flex-direction: column;
|
||||
.logo-img {
|
||||
display: none;
|
||||
}
|
||||
.name {
|
||||
margin-left: 0;
|
||||
height: auto;
|
||||
transform: none;
|
||||
text-align: center;
|
||||
.bg {
|
||||
font-size: 3.5rem;
|
||||
}
|
||||
.sm {
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
.description {
|
||||
margin-top: 2.5rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
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>
|
312
src/components/Music.vue
Normal file
@ -0,0 +1,312 @@
|
||||
<template>
|
||||
<!-- 音乐控制面板 -->
|
||||
<div
|
||||
class="music"
|
||||
@mouseenter="volumeShow = true"
|
||||
@mouseleave="volumeShow = false"
|
||||
v-show="store.musicOpenState"
|
||||
>
|
||||
<div class="btns">
|
||||
<span @click="openMusicList()">音乐列表</span>
|
||||
<span @click="store.musicOpenState = false">回到一言</span>
|
||||
</div>
|
||||
<div class="control">
|
||||
<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>
|
||||
</Transition>
|
||||
<go-end theme="filled" size="30" fill="#efefef" @click="changeMusicIndex(1)" />
|
||||
</div>
|
||||
<div class="menu">
|
||||
<div class="name" v-show="!volumeShow">
|
||||
<span>{{
|
||||
store.getPlayerData.name
|
||||
? store.getPlayerData.name + " - " + store.getPlayerData.artist
|
||||
: "未播放音乐"
|
||||
}}</span>
|
||||
</div>
|
||||
<div class="volume" v-show="volumeShow">
|
||||
<div class="icon">
|
||||
<volume-mute theme="filled" size="24" fill="#efefef" v-if="volumeNum == 0" />
|
||||
<volume-small
|
||||
theme="filled"
|
||||
size="24"
|
||||
fill="#efefef"
|
||||
v-else-if="volumeNum > 0 && volumeNum < 0.7"
|
||||
/>
|
||||
<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" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 音乐列表弹窗 -->
|
||||
<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
|
||||
class="close"
|
||||
theme="filled"
|
||||
size="28"
|
||||
fill="#ffffff60"
|
||||
@click="closeMusicList()"
|
||||
/>
|
||||
<Player
|
||||
ref="playerRef"
|
||||
:songServer="playerData.server"
|
||||
:songType="playerData.type"
|
||||
:songId="playerData.id"
|
||||
:volume="volumeNum"
|
||||
/>
|
||||
</div>
|
||||
</Transition>
|
||||
</div>
|
||||
</Transition>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {
|
||||
GoStart,
|
||||
PlayOne,
|
||||
Pause,
|
||||
GoEnd,
|
||||
CloseOne,
|
||||
VolumeMute,
|
||||
VolumeSmall,
|
||||
VolumeNotice,
|
||||
} from "@icon-park/vue-next";
|
||||
import Player from "@/components/Player.vue";
|
||||
import { mainStore } from "@/store";
|
||||
const store = mainStore();
|
||||
|
||||
// 音量条数据
|
||||
const volumeShow = ref(false);
|
||||
const volumeNum = ref(store.musicVolume ? store.musicVolume : 0.7);
|
||||
|
||||
// 播放列表数据
|
||||
const musicListShow = ref(false);
|
||||
const playerRef = ref(null);
|
||||
const playerData = reactive({
|
||||
server: import.meta.env.VITE_SONG_SERVER,
|
||||
type: import.meta.env.VITE_SONG_TYPE,
|
||||
id: import.meta.env.VITE_SONG_ID,
|
||||
});
|
||||
|
||||
// 开启播放列表
|
||||
const openMusicList = () => {
|
||||
musicListShow.value = true;
|
||||
playerRef.value.toggleList();
|
||||
};
|
||||
|
||||
// 关闭播放列表
|
||||
const closeMusicList = () => {
|
||||
musicListShow.value = false;
|
||||
playerRef.value.toggleList();
|
||||
};
|
||||
|
||||
// 音乐播放暂停
|
||||
const changePlayState = () => {
|
||||
playerRef.value.playToggle();
|
||||
};
|
||||
|
||||
// 音乐上下曲
|
||||
const changeMusicIndex = (type) => {
|
||||
playerRef.value.changeSong(type);
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
// 空格键事件
|
||||
window.addEventListener("keydown", (e) => {
|
||||
if (!store.musicIsOk) {
|
||||
return;
|
||||
}
|
||||
if (e.code == "Space") {
|
||||
changePlayState();
|
||||
}
|
||||
});
|
||||
// 挂载方法至 window
|
||||
window.$openList = openMusicList;
|
||||
});
|
||||
|
||||
// 监听音量变化
|
||||
watch(
|
||||
() => volumeNum.value,
|
||||
(value) => {
|
||||
store.musicVolume = value;
|
||||
playerRef.value.changeVolume(store.musicVolume);
|
||||
},
|
||||
);
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.music {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: #00000040;
|
||||
backdrop-filter: blur(10px);
|
||||
border-radius: 6px;
|
||||
padding: 20px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
animation: fade 0.5s;
|
||||
.btns {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 6px;
|
||||
span {
|
||||
background: #ffffff26;
|
||||
padding: 2px 8px;
|
||||
border-radius: 6px;
|
||||
margin: 0px 6px;
|
||||
text-overflow: ellipsis;
|
||||
overflow-x: hidden;
|
||||
white-space: nowrap;
|
||||
&:hover {
|
||||
background: #ffffff4d;
|
||||
}
|
||||
}
|
||||
}
|
||||
.control {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-evenly;
|
||||
width: 100%;
|
||||
.state {
|
||||
transition: opacity 0.1s;
|
||||
.i-icon {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
.i-icon {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
display: flex;
|
||||
border-radius: 6px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 6px;
|
||||
transform: scale(1);
|
||||
&:hover {
|
||||
background: #ffffff33;
|
||||
}
|
||||
&:active {
|
||||
transform: scale(0.95);
|
||||
}
|
||||
}
|
||||
}
|
||||
.menu {
|
||||
height: 26px;
|
||||
width: 100%;
|
||||
line-height: 26px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
.name {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
text-overflow: ellipsis;
|
||||
overflow-x: hidden;
|
||||
white-space: nowrap;
|
||||
animation: fade 0.3s;
|
||||
}
|
||||
.volume {
|
||||
width: 100%;
|
||||
padding: 0 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: row;
|
||||
animation: fade 0.3s;
|
||||
.icon {
|
||||
margin-right: 12px;
|
||||
span {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
:deep(*) {
|
||||
transition: none;
|
||||
}
|
||||
:deep(.el-slider__button) {
|
||||
transition: 0.3s;
|
||||
}
|
||||
.el-slider {
|
||||
margin-right: 12px;
|
||||
--el-slider-main-bg-color: #efefef;
|
||||
--el-slider-runway-bg-color: #ffffff40;
|
||||
--el-slider-button-size: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.music-list {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
margin: auto;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: #00000080;
|
||||
backdrop-filter: blur(20px);
|
||||
z-index: 1;
|
||||
.list {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
top: calc(50% - 300px);
|
||||
left: calc(50% - 320px);
|
||||
width: 640px;
|
||||
height: 600px;
|
||||
background-color: #ffffff66;
|
||||
border-radius: 6px;
|
||||
z-index: 999;
|
||||
@media (max-width: 720px) {
|
||||
left: calc(50% - 45%);
|
||||
width: 90%;
|
||||
}
|
||||
.close {
|
||||
position: absolute;
|
||||
top: 12px;
|
||||
right: 12px;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
display: block;
|
||||
&:hover {
|
||||
transform: scale(1.2);
|
||||
}
|
||||
&:active {
|
||||
transform: scale(0.95);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 弹窗动画
|
||||
.zoom-enter-active {
|
||||
animation: zoom 0.4s ease-in-out;
|
||||
}
|
||||
.zoom-leave-active {
|
||||
animation: zoom 0.3s ease-in-out reverse;
|
||||
}
|
||||
@keyframes zoom {
|
||||
0% {
|
||||
opacity: 0;
|
||||
transform: scale(0) translateY(-600px);
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
transform: scale(1) translateY(0);
|
||||
}
|
||||
}
|
||||
</style>
|
288
src/components/Player.vue
Normal file
@ -0,0 +1,288 @@
|
||||
<template>
|
||||
<APlayer
|
||||
v-if="playList[0]"
|
||||
ref="player"
|
||||
:audio="playList"
|
||||
:autoplay="store.playerAutoplay"
|
||||
:theme="theme"
|
||||
:autoSwitch="false"
|
||||
:loop="store.playerLoop"
|
||||
:order="store.playerOrder"
|
||||
:volume="volume"
|
||||
:showLrc="true"
|
||||
:listFolded="listFolded"
|
||||
:listMaxHeight="listMaxHeight"
|
||||
:noticeSwitch="false"
|
||||
@play="onPlay"
|
||||
@pause="onPause"
|
||||
@timeupdate="onTimeUp"
|
||||
@error="loadMusicError"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { MusicOne, PlayWrong } from "@icon-park/vue-next";
|
||||
import { getPlayerList } from "@/api";
|
||||
import { mainStore } from "@/store";
|
||||
import APlayer from "@worstone/vue-aplayer";
|
||||
|
||||
const store = mainStore();
|
||||
|
||||
// 获取播放器 DOM
|
||||
const player = ref(null);
|
||||
|
||||
// 歌曲播放列表
|
||||
const playList = ref([]);
|
||||
|
||||
// 歌曲播放项
|
||||
const playIndex = ref(0);
|
||||
|
||||
// 配置项
|
||||
const props = defineProps({
|
||||
// 主题色
|
||||
theme: {
|
||||
type: String,
|
||||
default: "#efefef",
|
||||
},
|
||||
// 默认音量
|
||||
volume: {
|
||||
type: Number,
|
||||
default: 0.7,
|
||||
validator: (value) => {
|
||||
return value >= 0 && value <= 1;
|
||||
},
|
||||
},
|
||||
// 歌曲服务器 ( netease-网易云, tencent-qq音乐 )
|
||||
songServer: {
|
||||
type: String,
|
||||
default: "netease", //'netease' | 'tencent'
|
||||
},
|
||||
// 播放类型 ( song-歌曲, playlist-播放列表, album-专辑, search-搜索, artist-艺术家 )
|
||||
songType: {
|
||||
type: String,
|
||||
default: "playlist",
|
||||
},
|
||||
// id
|
||||
songId: {
|
||||
type: String,
|
||||
default: "7452421335",
|
||||
},
|
||||
// 列表是否默认折叠
|
||||
listFolded: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
// 列表最大高度
|
||||
listMaxHeight: {
|
||||
type: Number,
|
||||
default: 420,
|
||||
},
|
||||
});
|
||||
|
||||
const listHeight = computed(() => {
|
||||
return props.listMaxHeight + "px";
|
||||
});
|
||||
|
||||
// 初始化播放器
|
||||
onMounted(() => {
|
||||
nextTick(() => {
|
||||
try {
|
||||
getPlayerList(props.songServer, props.songType, props.songId).then((res) => {
|
||||
console.log(res);
|
||||
// 更改播放器加载状态
|
||||
store.musicIsOk = true;
|
||||
// 生成歌单
|
||||
playList.value = res;
|
||||
console.log("音乐加载完成");
|
||||
console.log(playList.value);
|
||||
console.log(playIndex.value, playList.value.length, props.volume);
|
||||
});
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
store.musicIsOk = false;
|
||||
ElMessage({
|
||||
message: "播放器加载失败",
|
||||
grouping: true,
|
||||
icon: h(PlayWrong, {
|
||||
theme: "filled",
|
||||
fill: "#efefef",
|
||||
}),
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 播放
|
||||
const onPlay = () => {
|
||||
console.log("播放");
|
||||
playIndex.value = player.value.aplayer.index;
|
||||
// 播放状态
|
||||
store.setPlayerState(player.value.audioRef.paused);
|
||||
// 储存播放器信息
|
||||
store.setPlayerData(playList.value[playIndex.value].name, playList.value[playIndex.value].artist);
|
||||
ElMessage({
|
||||
message: store.getPlayerData.name + " - " + store.getPlayerData.artist,
|
||||
grouping: true,
|
||||
icon: h(MusicOne, {
|
||||
theme: "filled",
|
||||
fill: "#efefef",
|
||||
}),
|
||||
});
|
||||
};
|
||||
|
||||
// 暂停
|
||||
const onPause = () => {
|
||||
store.setPlayerState(player.value.audioRef.paused);
|
||||
};
|
||||
|
||||
// 音频时间更新事件
|
||||
const onTimeUp = () => {
|
||||
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);
|
||||
};
|
||||
|
||||
// 切换播放暂停事件
|
||||
const playToggle = () => {
|
||||
player.value.toggle();
|
||||
};
|
||||
|
||||
// 切换音量事件
|
||||
const changeVolume = (value) => {
|
||||
player.value.setVolume(value, false);
|
||||
};
|
||||
|
||||
// 切换上下曲
|
||||
const changeSong = (type) => {
|
||||
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, toggleList });
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.aplayer {
|
||||
width: 80%;
|
||||
border-radius: 6px;
|
||||
font-family: "HarmonyOS_Regular", sans-serif !important;
|
||||
:deep(.aplayer-body) {
|
||||
background-color: transparent;
|
||||
.aplayer-pic {
|
||||
display: none;
|
||||
}
|
||||
.aplayer-info {
|
||||
margin-left: 0;
|
||||
background-color: #ffffff40;
|
||||
border-color: transparent !important;
|
||||
.aplayer-music {
|
||||
flex-grow: initial;
|
||||
margin-bottom: 2px;
|
||||
overflow: initial;
|
||||
.aplayer-title {
|
||||
font-size: 16px;
|
||||
margin-right: 6px;
|
||||
}
|
||||
.aplayer-author {
|
||||
color: #efefef;
|
||||
}
|
||||
}
|
||||
.aplayer-lrc {
|
||||
text-align: left;
|
||||
margin: 7px 0 6px 6px;
|
||||
height: 44px;
|
||||
mask: linear-gradient(
|
||||
#fff 15%,
|
||||
#fff 85%,
|
||||
hsla(0deg, 0%, 100%, 0.6) 90%,
|
||||
hsla(0deg, 0%, 100%, 0)
|
||||
);
|
||||
-webkit-mask: linear-gradient(
|
||||
#fff 15%,
|
||||
#fff 85%,
|
||||
hsla(0deg, 0%, 100%, 0.6) 90%,
|
||||
hsla(0deg, 0%, 100%, 0)
|
||||
);
|
||||
&::before,
|
||||
&::after {
|
||||
display: none;
|
||||
}
|
||||
p {
|
||||
color: #efefef;
|
||||
}
|
||||
.aplayer-lrc-current {
|
||||
font-size: 0.95rem;
|
||||
margin-bottom: 4px !important;
|
||||
}
|
||||
}
|
||||
.aplayer-controller {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
:deep(.aplayer-list) {
|
||||
margin-top: 6px;
|
||||
height: v-bind(listHeight);
|
||||
background-color: transparent;
|
||||
ol {
|
||||
&::-webkit-scrollbar-track {
|
||||
background-color: transparent;
|
||||
}
|
||||
li {
|
||||
border-color: transparent;
|
||||
&.aplayer-list-light {
|
||||
background: #ffffff40;
|
||||
border-radius: 6px;
|
||||
}
|
||||
&:hover {
|
||||
background: #ffffff26 !important;
|
||||
border-radius: 6px !important;
|
||||
}
|
||||
.aplayer-list-index,
|
||||
.aplayer-list-author {
|
||||
color: #efefef;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
202
src/components/Set.vue
Normal file
@ -0,0 +1,202 @@
|
||||
<template>
|
||||
<div class="setting">
|
||||
<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 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>
|
||||
<el-collapse-item title="个性化调整" name="2">
|
||||
<div class="item">
|
||||
<span class="text">建站日期显示</span>
|
||||
<el-switch
|
||||
v-model="siteStartShow"
|
||||
inline-prompt
|
||||
:active-icon="CheckSmall"
|
||||
:inactive-icon="CloseSmall"
|
||||
/>
|
||||
</div>
|
||||
<div class="item">
|
||||
<span class="text">音乐点击是否打开面板</span>
|
||||
<el-switch
|
||||
v-model="musicClick"
|
||||
inline-prompt
|
||||
:active-icon="CheckSmall"
|
||||
:inactive-icon="CloseSmall"
|
||||
/>
|
||||
</div>
|
||||
<div class="item">
|
||||
<span class="text">底栏歌词显示</span>
|
||||
<el-switch
|
||||
v-model="playerLrcShow"
|
||||
inline-prompt
|
||||
:active-icon="CheckSmall"
|
||||
:inactive-icon="CloseSmall"
|
||||
/>
|
||||
</div>
|
||||
<div class="item">
|
||||
<span class="text">底栏背景模糊</span>
|
||||
<el-switch
|
||||
v-model="footerBlur"
|
||||
inline-prompt
|
||||
:active-icon="CheckSmall"
|
||||
:inactive-icon="CloseSmall"
|
||||
/>
|
||||
</div>
|
||||
</el-collapse-item>
|
||||
<el-collapse-item title="播放器配置" name="3">
|
||||
<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>
|
||||
</el-collapse-item>
|
||||
</el-collapse>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { CheckSmall, CloseSmall, SuccessPicture } from "@icon-park/vue-next";
|
||||
import { mainStore } from "@/store";
|
||||
import { storeToRefs } from "pinia";
|
||||
|
||||
const store = mainStore();
|
||||
const {
|
||||
coverType,
|
||||
siteStartShow,
|
||||
musicClick,
|
||||
playerLrcShow,
|
||||
footerBlur,
|
||||
playerAutoplay,
|
||||
playerOrder,
|
||||
playerLoop,
|
||||
} = storeToRefs(store);
|
||||
|
||||
// 默认选中项
|
||||
const activeName = ref("1");
|
||||
|
||||
// 壁纸切换
|
||||
const radioChange = () => {
|
||||
ElMessage({
|
||||
message: "壁纸更换成功",
|
||||
icon: h(SuccessPicture, {
|
||||
theme: "filled",
|
||||
fill: "#efefef",
|
||||
}),
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.setting {
|
||||
.collapse {
|
||||
border-radius: 8px;
|
||||
--el-collapse-content-bg-color: #ffffff10;
|
||||
border-color: transparent;
|
||||
overflow: hidden;
|
||||
|
||||
:deep(.el-collapse-item__header) {
|
||||
background-color: #ffffff30;
|
||||
color: #fff;
|
||||
font-size: 15px;
|
||||
padding-left: 18px;
|
||||
border-color: transparent;
|
||||
}
|
||||
|
||||
:deep(.el-collapse-item__wrap) {
|
||||
border-color: transparent;
|
||||
|
||||
.el-collapse-item__content {
|
||||
padding: 20px;
|
||||
.item {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.el-radio-group {
|
||||
justify-content: space-between;
|
||||
|
||||
.el-radio {
|
||||
margin: 10px 16px;
|
||||
background: #ffffff26;
|
||||
border: 2px solid transparent;
|
||||
border-radius: 8px;
|
||||
|
||||
.el-radio__label {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.el-radio__inner {
|
||||
background: #ffffff06 !important;
|
||||
border: 2px solid #eeeeee !important;
|
||||
}
|
||||
|
||||
&.is-checked {
|
||||
background: #ffffff06 !important;
|
||||
border: 2px solid #eeeeee !important;
|
||||
}
|
||||
|
||||
.is-checked {
|
||||
.el-radio__inner {
|
||||
background-color: #ffffff30 !important;
|
||||
border-color: #fff !important;
|
||||
}
|
||||
|
||||
& + .el-radio__label {
|
||||
color: #fff !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
88
src/components/SocialLinks.vue
Normal file
@ -0,0 +1,88 @@
|
||||
<template>
|
||||
<!-- 社交链接 -->
|
||||
<div class="social">
|
||||
<div class="link">
|
||||
<a
|
||||
v-for="item in socialLinks"
|
||||
:key="item.name"
|
||||
:href="item.url"
|
||||
target="_blank"
|
||||
@mouseenter="socialTip = item.tip"
|
||||
@mouseleave="socialTip = '通过这里联系我吧'"
|
||||
>
|
||||
<img class="icon" :src="item.icon" height="24" />
|
||||
</a>
|
||||
</div>
|
||||
<span class="tip">{{ socialTip }}</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import socialLinks from "@/assets/socialLinks.json";
|
||||
|
||||
// 社交链接提示
|
||||
const socialTip = ref("通过这里联系我吧");
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.social {
|
||||
margin-top: 1rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
max-width: 460px;
|
||||
width: 100%;
|
||||
height: 42px;
|
||||
background-color: transparent;
|
||||
border-radius: 6px;
|
||||
backdrop-filter: blur(0);
|
||||
animation: fade 0.5s;
|
||||
transition:
|
||||
background-color 0.3s,
|
||||
backdrop-filter 0.3s;
|
||||
@media (max-width: 840px) {
|
||||
max-width: 100%;
|
||||
justify-content: center;
|
||||
.link {
|
||||
justify-content: space-evenly !important;
|
||||
width: 90%;
|
||||
}
|
||||
.tip {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
.link {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
a {
|
||||
display: inherit;
|
||||
.icon {
|
||||
margin: 0 12px;
|
||||
transition: transform 0.3s;
|
||||
&:hover {
|
||||
transform: scale(1.1);
|
||||
}
|
||||
&:active {
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.tip {
|
||||
display: none;
|
||||
margin-right: 12px;
|
||||
animation: fade 0.5s;
|
||||
}
|
||||
@media (min-width: 768px) {
|
||||
&:hover {
|
||||
background-color: #00000040;
|
||||
backdrop-filter: blur(5px);
|
||||
.tip {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
98
src/components/TimeCapsule.vue
Normal file
@ -0,0 +1,98 @@
|
||||
<template>
|
||||
<div class="time-capsule">
|
||||
<div class="title">
|
||||
<hourglass-full theme="two-tone" size="24" :fill="['#efefef', '#00000020']" />
|
||||
<span>时光胶囊</span>
|
||||
</div>
|
||||
<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>
|
||||
|
||||
<script setup>
|
||||
import { HourglassFull } from "@icon-park/vue-next";
|
||||
import { getTimeCapsule, siteDateStatistics } from "@/utils/getTime.js";
|
||||
import { mainStore } from "@/store";
|
||||
const store = mainStore();
|
||||
|
||||
// 进度条数据
|
||||
const timeData = ref(getTimeCapsule());
|
||||
const startDate = ref(import.meta.env.VITE_SITE_START);
|
||||
const startDateText = ref(null);
|
||||
const timeInterval = ref(null);
|
||||
|
||||
onMounted(() => {
|
||||
timeInterval.value = setInterval(() => {
|
||||
timeData.value = getTimeCapsule();
|
||||
if (startDate.value) startDateText.value = siteDateStatistics(new Date(startDate.value));
|
||||
}, 1000);
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
clearInterval(timeInterval.value);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.time-capsule {
|
||||
width: 100%;
|
||||
.title {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
margin: 0.2rem 0 1.5rem;
|
||||
font-size: 1.1rem;
|
||||
.i-icon {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin-right: 6px;
|
||||
}
|
||||
}
|
||||
.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>
|
114
src/components/Weather.vue
Normal file
@ -0,0 +1,114 @@
|
||||
<template>
|
||||
<div class="weather" v-if="weatherData.adCode.city && weatherData.weather.weather">
|
||||
<span>{{ weatherData.adCode.city }} </span>
|
||||
<span>{{ weatherData.weather.weather }} </span>
|
||||
<span>{{ weatherData.weather.temperature }}℃</span>
|
||||
<span class="sm-hidden">
|
||||
{{
|
||||
weatherData.weather.winddirection?.endsWith("风")
|
||||
? weatherData.weather.winddirection
|
||||
: weatherData.weather.winddirection + "风"
|
||||
}}
|
||||
</span>
|
||||
<span class="sm-hidden">{{ weatherData.weather.windpower }} 级</span>
|
||||
</div>
|
||||
<div class="weather" v-else>
|
||||
<span>天气数据获取失败</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { getAdcode, getWeather, getOtherWeather } from "@/api";
|
||||
import { Error } from "@icon-park/vue-next";
|
||||
|
||||
// 高德开发者 Key
|
||||
const mainKey = import.meta.env.VITE_WEATHER_KEY;
|
||||
|
||||
// 天气数据
|
||||
const weatherData = reactive({
|
||||
adCode: {
|
||||
city: null, // 城市
|
||||
adcode: null, // 城市编码
|
||||
},
|
||||
weather: {
|
||||
weather: null, // 天气现象
|
||||
temperature: null, // 实时气温
|
||||
winddirection: null, // 风向描述
|
||||
windpower: null, // 风力级别
|
||||
},
|
||||
});
|
||||
|
||||
// 取出天气平均值
|
||||
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 = async () => {
|
||||
try {
|
||||
// 获取地理位置信息
|
||||
if (!mainKey) {
|
||||
console.log("未配置,使用备用天气接口");
|
||||
const result = await getOtherWeather();
|
||||
console.log(result);
|
||||
const data = result.result;
|
||||
weatherData.adCode = {
|
||||
city: data.city.City || "未知地区",
|
||||
// adcode: data.city.cityId,
|
||||
};
|
||||
weatherData.weather = {
|
||||
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,
|
||||
};
|
||||
} else {
|
||||
// 获取 Adcode
|
||||
const adCode = await getAdcode(mainKey);
|
||||
console.log(adCode);
|
||||
if (adCode.infocode !== "10000") {
|
||||
throw "地区查询失败";
|
||||
}
|
||||
weatherData.adCode = {
|
||||
city: adCode.city,
|
||||
adcode: adCode.adcode,
|
||||
};
|
||||
// 获取天气信息
|
||||
const result = await getWeather(mainKey, weatherData.adCode.adcode);
|
||||
weatherData.weather = {
|
||||
weather: result.lives[0].weather,
|
||||
temperature: result.lives[0].temperature,
|
||||
winddirection: result.lives[0].winddirection,
|
||||
windpower: result.lives[0].windpower,
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("天气信息获取失败:" + error);
|
||||
onError("天气信息获取失败");
|
||||
}
|
||||
};
|
||||
|
||||
// 报错信息
|
||||
const onError = (message) => {
|
||||
ElMessage({
|
||||
message,
|
||||
icon: h(Error, {
|
||||
theme: "filled",
|
||||
fill: "#efefef",
|
||||
}),
|
||||
});
|
||||
console.error(message);
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
// 调用获取天气
|
||||
getWeatherData();
|
||||
});
|
||||
</script>
|
22
src/main.js
Normal file
@ -0,0 +1,22 @@
|
||||
import { createApp } from "vue";
|
||||
import "@/style/style.scss";
|
||||
import App from "@/App.vue";
|
||||
// 引入 pinia
|
||||
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");
|
||||
|
||||
// PWA
|
||||
navigator.serviceWorker.addEventListener("controllerchange", () => {
|
||||
// 弹出更新提醒
|
||||
console.log("站点已更新,刷新后生效");
|
||||
ElMessage("站点已更新,刷新后生效");
|
||||
});
|
93
src/store/index.js
Normal file
@ -0,0 +1,93 @@
|
||||
import { defineStore } from "pinia";
|
||||
|
||||
export const mainStore = defineStore("main", {
|
||||
state: () => {
|
||||
return {
|
||||
imgLoadStatus: false, // 壁纸加载状态
|
||||
innerWidth: null, // 当前窗口宽度
|
||||
coverType: "0", // 壁纸种类
|
||||
siteStartShow: false, // 建站日期显示
|
||||
musicClick: false, // 音乐链接是否跳转
|
||||
musicIsOk: false, // 音乐是否加载完成
|
||||
musicVolume: 0, // 音乐音量;
|
||||
musicOpenState: false, // 音乐面板开启状态
|
||||
backgroundShow: false, // 壁纸展示状态
|
||||
boxOpenState: false, // 盒子开启状态
|
||||
mobileOpenState: false, // 移动端开启状态
|
||||
mobileFuncState: false, // 移动端功能区开启状态
|
||||
setOpenState: false, // 设置页面开启状态
|
||||
playerState: false, // 当前播放状态
|
||||
playerTitle: null, // 当前播放歌曲名
|
||||
playerArtist: null, // 当前播放歌手名
|
||||
playerLrc: "歌词加载中", // 当前播放歌词
|
||||
playerLrcShow: true, // 是否显示底栏歌词
|
||||
footerBlur: true, // 底栏模糊
|
||||
playerAutoplay: false, // 是否自动播放
|
||||
playerLoop: "all", // 循环播放 "all", "one", "none"
|
||||
playerOrder: "list", // 循环顺序 "list", "random"
|
||||
};
|
||||
},
|
||||
getters: {
|
||||
// 获取歌词
|
||||
getPlayerLrc(state) {
|
||||
return state.playerLrc;
|
||||
},
|
||||
// 获取歌曲信息
|
||||
getPlayerData(state) {
|
||||
return {
|
||||
name: state.playerTitle,
|
||||
artist: state.playerArtist,
|
||||
};
|
||||
},
|
||||
// 获取页面宽度
|
||||
getInnerWidth(state) {
|
||||
return state.innerWidth;
|
||||
},
|
||||
},
|
||||
actions: {
|
||||
// 更改当前页面宽度
|
||||
setInnerWidth(value) {
|
||||
this.innerWidth = value;
|
||||
if (value >= 720) {
|
||||
this.mobileOpenState = false;
|
||||
this.mobileFuncState = false;
|
||||
}
|
||||
},
|
||||
// 更改播放状态
|
||||
setPlayerState(value) {
|
||||
if (value) {
|
||||
this.playerState = false;
|
||||
} else {
|
||||
this.playerState = true;
|
||||
}
|
||||
},
|
||||
// 更改歌词
|
||||
setPlayerLrc(value) {
|
||||
this.playerLrc = value;
|
||||
},
|
||||
// 更改歌曲数据
|
||||
setPlayerData(title, artist) {
|
||||
this.playerTitle = title;
|
||||
this.playerArtist = artist;
|
||||
},
|
||||
// 更改壁纸加载状态
|
||||
setImgLoadStatus(value) {
|
||||
this.imgLoadStatus = value;
|
||||
},
|
||||
},
|
||||
persist: {
|
||||
key: "data",
|
||||
storage: window.localStorage,
|
||||
paths: [
|
||||
"coverType",
|
||||
"musicVolume",
|
||||
"siteStartShow",
|
||||
"musicClick",
|
||||
"playerLrcShow",
|
||||
"footerBlur",
|
||||
"playerAutoplay",
|
||||
"playerLoop",
|
||||
"playerOrder",
|
||||
],
|
||||
},
|
||||
});
|
36
src/style/global.scss
Normal file
@ -0,0 +1,36 @@
|
||||
// scss 全局变量
|
||||
|
||||
// 响应式布局
|
||||
@mixin changeWidth($maxWidth: 1200px) {
|
||||
.container {
|
||||
max-width: $maxWidth;
|
||||
}
|
||||
}
|
||||
|
||||
// 首次调用
|
||||
@include changeWidth;
|
||||
|
||||
/* 小于1380px时 */
|
||||
@media (max-width: 1380px) {
|
||||
.el-radio-group {
|
||||
justify-content: center !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* 小于1280px时 */
|
||||
@media (max-width: 1280px) {
|
||||
@include changeWidth($maxWidth: 1100px);
|
||||
}
|
||||
|
||||
/* 小于992px时 */
|
||||
@media (max-width: 992px) {
|
||||
@include changeWidth($maxWidth: 900px);
|
||||
}
|
||||
|
||||
/* 小于720px时 */
|
||||
@media (max-width: 720px) {
|
||||
// 隐藏元素
|
||||
.xs-hidden {
|
||||
display: none;
|
||||
}
|
||||
}
|
228
src/style/style.scss
Normal file
@ -0,0 +1,228 @@
|
||||
/*
|
||||
作者: imsyy
|
||||
主页:https://www.imsyy.top/
|
||||
GitHub:https://github.com/imsyy/home
|
||||
版权所有,请勿删除
|
||||
*/
|
||||
|
||||
@charset "utf-8";
|
||||
|
||||
/*全局样式*/
|
||||
|
||||
html,
|
||||
body {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
// width: 100dvh;
|
||||
// height: 100dvh;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
background-color: #333;
|
||||
overflow: hidden;
|
||||
font-family: "HarmonyOS_Regular", sans-serif;
|
||||
}
|
||||
|
||||
*,
|
||||
a,
|
||||
p {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
user-select: none;
|
||||
text-decoration: none;
|
||||
color: #fff;
|
||||
box-sizing: border-box;
|
||||
|
||||
&:hover {
|
||||
transition: 0.3s;
|
||||
}
|
||||
}
|
||||
|
||||
// 字体文件
|
||||
@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");
|
||||
}
|
||||
|
||||
// 基础样式
|
||||
#app {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
// 卡片样式
|
||||
.cards {
|
||||
border-radius: 6px;
|
||||
background-color: #00000040;
|
||||
backdrop-filter: blur(10px);
|
||||
transform: scale(1);
|
||||
transition:
|
||||
backdrop-filter 0.3s,
|
||||
transform 0.3s;
|
||||
&:hover {
|
||||
transform: scale(1.01);
|
||||
}
|
||||
&:active {
|
||||
transform: scale(0.98);
|
||||
}
|
||||
}
|
||||
|
||||
// 文字超出
|
||||
.text-hidden {
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
// 弹窗样式
|
||||
.el-message {
|
||||
--el-message-bg-color: #00000040 !important;
|
||||
--el-message-text-color: #efefef !important;
|
||||
-webkit-backdrop-filter: blur(10px);
|
||||
backdrop-filter: blur(10px);
|
||||
border-radius: 25px !important;
|
||||
border-color: transparent !important;
|
||||
|
||||
.el-message__badge {
|
||||
display: none;
|
||||
}
|
||||
.el-message__content {
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
// 进度条样式
|
||||
.el-progress-bar {
|
||||
.el-progress-bar__outer {
|
||||
border-radius: 6px;
|
||||
background-color: #00000020;
|
||||
.el-progress-bar__inner {
|
||||
background-color: #efefef;
|
||||
border-radius: 6px;
|
||||
text-align: center;
|
||||
font-family: "UnidreamLED";
|
||||
span {
|
||||
color: #564d59;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Tooltip 样式
|
||||
.el-popper.is-dark {
|
||||
background: #ffffff60 !important;
|
||||
border: 1px solid transparent !important;
|
||||
}
|
||||
|
||||
// 卡片样式
|
||||
.el-card {
|
||||
border-radius: 8px !important;
|
||||
border: 1px solid transparent !important;
|
||||
background-color: transparent !important;
|
||||
.el-card__header {
|
||||
font-weight: bold;
|
||||
padding: 16px 20px !important;
|
||||
background-color: #ffffff30 !important;
|
||||
border-bottom: 1px solid transparent !important;
|
||||
}
|
||||
.el-card__body {
|
||||
padding: 0 !important;
|
||||
background-color: #ffffff10 !important;
|
||||
}
|
||||
}
|
||||
|
||||
// Transition 动画
|
||||
.fade-enter-active,
|
||||
.fade-leave-active {
|
||||
transition: opacity 0.3s ease-in-out;
|
||||
}
|
||||
|
||||
.fade-enter-from,
|
||||
.fade-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
// keyframes 动画
|
||||
@keyframes fade {
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fade-blur-in {
|
||||
from {
|
||||
filter: blur(20px) brightness(0.3);
|
||||
transform: scale(1.6);
|
||||
}
|
||||
to {
|
||||
filter: blur(0) brightness(1);
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fade-blur-main-in {
|
||||
from {
|
||||
transform: scale(1.2);
|
||||
}
|
||||
to {
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
// 隐藏元素
|
||||
@media (min-width: 910px) and (max-width: 1200px) {
|
||||
.sm-hidden {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
// 自定义鼠标
|
||||
#cursor {
|
||||
position: fixed;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
background: #fff;
|
||||
border-radius: 25px;
|
||||
opacity: 0.25;
|
||||
z-index: 10086;
|
||||
pointer-events: none;
|
||||
transition: 0.2s ease-in-out;
|
||||
transition-property: background, opacity, transform;
|
||||
|
||||
&.hidden {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
&.active {
|
||||
opacity: 0.5;
|
||||
transform: scale(0.5);
|
||||
}
|
||||
}
|
||||
|
||||
// 滚动条样式
|
||||
::-webkit-scrollbar,
|
||||
scrollbar {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb,
|
||||
scrollbar-thumb {
|
||||
border-radius: 10px;
|
||||
background-color: #eeeeee;
|
||||
}
|
94
src/utils/cursor.js
Normal file
@ -0,0 +1,94 @@
|
||||
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) {
|
||||
console.error(e);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
const cursorInit = () => {
|
||||
mainCursor = new Cursor();
|
||||
return mainCursor;
|
||||
};
|
||||
|
||||
class Cursor {
|
||||
constructor() {
|
||||
this.pos = {
|
||||
curr: null,
|
||||
prev: null,
|
||||
};
|
||||
this.pt = [];
|
||||
this.create();
|
||||
this.init();
|
||||
this.render();
|
||||
}
|
||||
|
||||
move(left, top) {
|
||||
this.cursor.style["left"] = `${left}px`;
|
||||
this.cursor.style["top"] = `${top}px`;
|
||||
}
|
||||
|
||||
create() {
|
||||
if (!this.cursor) {
|
||||
this.cursor = document.createElement("div");
|
||||
this.cursor.id = "cursor";
|
||||
this.cursor.classList.add("xs-hidden");
|
||||
this.cursor.classList.add("hidden");
|
||||
document.body.append(this.cursor);
|
||||
}
|
||||
|
||||
var el = document.getElementsByTagName("*");
|
||||
for (let i = 0; i < el.length; i++)
|
||||
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}`;
|
||||
}
|
||||
|
||||
refresh() {
|
||||
this.scr.remove();
|
||||
this.cursor.classList.remove("active");
|
||||
this.pos = {
|
||||
curr: null,
|
||||
prev: null,
|
||||
};
|
||||
this.pt = [];
|
||||
|
||||
this.create();
|
||||
this.init();
|
||||
this.render();
|
||||
}
|
||||
|
||||
init() {
|
||||
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,
|
||||
};
|
||||
this.cursor.classList.remove("hidden");
|
||||
};
|
||||
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() {
|
||||
if (this.pos.prev) {
|
||||
this.pos.prev.x = Math.lerp(this.pos.prev.x, this.pos.curr.x, 0.35);
|
||||
this.pos.prev.y = Math.lerp(this.pos.prev.y, this.pos.curr.y, 0.35);
|
||||
this.move(this.pos.prev.x, this.pos.prev.y);
|
||||
} else {
|
||||
this.pos.prev = this.pos.curr;
|
||||
}
|
||||
requestAnimationFrame(() => this.render());
|
||||
}
|
||||
}
|
||||
|
||||
export default cursorInit;
|